当前位置: 代码迷 >> 综合 >> BZOJ 4521 [Cqoi2016] 手机号码
  详细解决方案

BZOJ 4521 [Cqoi2016] 手机号码

热度:52   发布时间:2024-01-19 02:13:56.0

Description

人们选择手机号码时都希望号码好记、吉利。比如号码中含有几位相邻的相同数字、不含谐音不
吉利的数字等。手机运营商在发行新号码时也会考虑这些因素,从号段中选取含有某些特征的号
码单独出售。为了便于前期规划,运营商希望开发一个工具来自动统计号段中满足特征的号码数
量。
工具需要检测的号码特征有两个:号码中要出现至少3个相邻的相同数字,号码中不能同
时出现8和4。号码必须同时包含两个特征才满足条件。满足条件的号码例如:13000988721、
23333333333、14444101000。而不满足条件的号码例如:1015400080、10010012022。
手机号码一定是11位数,前不含前导的0。工具接收两个数L和R,自动统计出[L,R]区间
内所有满足条件的号码数量。L和R也是11位的手机号码。

Input

输入文件内容只有一行,为空格分隔的2个正整数L,R。
10^10 < =  L < =  R < 10^11

Output

输出文件内容只有一行,为1个整数,表示满足条件的手机号数量。

Sample Input

12121284000 12121285550

Sample Output

5
样例解释
满足条件的号码: 12121285000、 12121285111、 12121285222、 12121285333、 12121285550

HINT

Source

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

数位DP~

用f[i][j][k][x][y][z][lo][hi]表示目前已填i位,第i+1位填j,已经连续k位相同,x==1 ? 有:没有连续三位相同,y==1 ?  有:没有4,z==1 ? 有:没有8。

(注意其中所有位都是从高位往低位DP,从第1位到第11位就是大家观察数的时候的顺序。)

所以用i小的更新i大的,最后统计即可。

过程中学了某神犇的位运算优化,简化了不少,位运算真是好用~


#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
#define ll long longint l[12],r[12];
ll f[12][10][12][2][2][2][2][2],ans;
char le[11],ri[11];int main()
{scanf("%s%s",le,ri);for(int i=0;i<11;i++) l[i+1]=le[i]-'0',r[i+1]=ri[i]-'0';for(int i=l[1];i<=r[1];i++) f[1][i][1][0][i==4][i==8][i==l[1]][i==r[1]]=1;for(int i=1;i<=10;i++)for(int j=0;j<=9;j++)for(int k=0;k<=i;k++)for(int x=0;x<=1;x++)for(int y=0;y<=1;y++)for(int z=0;z<=1;z++)for(int lo=0;lo<=1;lo++)for(int hi=0;hi<=1;hi++)if(f[i][j][k][x][y][z]){if(lo && hi){for(int ii=l[i+1];ii<=r[i+1];ii++)if(ii==j) f[i+1][ii][k+1][x|(k>=2)][y|(ii==4)][z|(ii==8)][lo&(ii==l[i+1])][hi&(ii==r[i+1])]+=f[i][j][k][x][y][z][lo][hi];else f[i+1][ii][1][x][y|(ii==4)][z|(ii==8)][lo&(ii==l[i+1])][hi&(ii==r[i+1])]+=f[i][j][k][x][y][z][lo][hi];continue;}if(!lo && !hi){for(int ii=0;ii<=9;ii++)if(ii==j) f[i+1][ii][k+1][x|(k>=2)][y|(ii==4)][z|(ii==8)][0][0]+=f[i][j][k][x][y][z][lo][hi];else f[i+1][ii][1][x][y|(ii==4)][z|(ii==8)][0][0]+=f[i][j][k][x][y][z][lo][hi];continue;}if(!lo && hi){for(int ii=0;ii<=r[i+1];ii++)if(ii==j) f[i+1][ii][k+1][x|(k>=2)][y|(ii==4)][z|(ii==8)][lo&(ii==l[i+1])][hi&(ii==r[i+1])]+=f[i][j][k][x][y][z][lo][hi];else f[i+1][ii][1][x][y|(ii==4)][z|(ii==8)][lo&(ii==l[i+1])][hi&(ii==r[i+1])]+=f[i][j][k][x][y][z][lo][hi];continue;}if(lo && !hi){for(int ii=l[i+1];ii<=9;ii++)if(ii==j) f[i+1][ii][k+1][x|(k>=2)][y|(ii==4)][z|(ii==8)][lo&(ii==l[i+1])][hi&(ii==r[i+1])]+=f[i][j][k][x][y][z][lo][hi];else f[i+1][ii][1][x][y|(ii==4)][z|(ii==8)][lo&(ii==l[i+1])][hi&(ii==r[i+1])]+=f[i][j][k][x][y][z][lo][hi];continue;}}for(int i=0;i<=9;i++)for(int j=1;j<=11;j++)for(int x=0;x<=1;x++)for(int y=0;y<=1;y++) ans+=f[11][i][j][1][0][0][x][y]+f[11][i][j][1][1][0][x][y]+f[11][i][j][1][0][1][x][y];printf("%lld\n",ans);return 0;
}