神奇的数位DP--HDU2089
//旷掉了语文课QAQ我有点方
//课件看懂了,就来码了一下,因为HDU好像不给我交,也不知道是否正确
//题目大意是在一个区间内查询数字中不含“62”和“4”的数的个数,允许前导零
//就是用数位DP,在已经做过的前缀上加数,改方案数
//这里是修改前错误的代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 1000000
int n,m,f[10][11];
void printff()
{
for(int i=1;i<=6;i++)
{
for(int j=0;j<=9;j++) printf("%d ",f[i][j]);
printf("\n");
}
}
int find(int x)
{
int last=0;
while(x>0)
{
if(x%10==4||last==2&&x%10==6) return 0;
last=x%10;
x/=10;
}
return 1;
}
int ask(int x)
{
int ans=0,c=0;
while(x>0)
{
c++;
for(int i=0;i<=x%10-1;i++)
ans+=f[c][i];
x/=10;
}
printf("%d %d\n",c,ans);
return ans;
}
int main()
{
memset(f,0,sizeof(int));
for(int i=0;i<=9;i++) f[1][i]=1;//第一位的时候每个数字除了4方案都是1
f[1][4]=0;
for(int i=2;i<=7;i++)//最多只有六位
for(int j=0;j<=9;j++)//枚举当前位
for(int k=0;k<=9;k++)//枚举前一位
if(j!=4&&(!(j==6&&k==2)))
f[i][j]+=f[i-1][k];
printff();
while(1)
{
scanf("%d%d",&n,&m);
if(n==0&&m==0) break;
printf("%d",ask(m)-ask(n)+find(m));
}
}
//这里是正确的
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 1000000
int n,m,f[10][11];
int find(int &x)
{
int mark=x,total=0,c=1;
while(x>0)
{
if(x%10==4)
{
x=mark-total-1;
return 0;
}
total=total+(x%10)*c;
c=c*10;
x/=10;
}
x=total;
return 1;
}
int ask(int x)
{
int last=x,ans=0,c=0;
while(!find(x));
while(x>0)
{
c++;
for(int i=0;i<=x%10-1;i++)
ans+=f[c][i];
x/=10;
}
return ans;
}
void printff()
{
for(int i=1;i<=100;i++)
{
printf("%d ",ask(i));
if(i%10==0) printf("\n");
}
}
int main()
{
memset(f,0,sizeof(int));
for(int i=0;i<=9;i++) f[1][i]=1;//第一位的时候每个数字除了4方案都是1
f[1][4]=0;
for(int i=2;i<=7;i++)//最多只有六位
for(int j=0;j<=9;j++)//枚举当前位
for(int k=0;k<=9;k++)//枚举前一位
if(j!=4&&(!(j==6&&k==2)))
f[i][j]+=f[i-1][k];
while(1)
{
scanf("%d%d",&n,&m);
if(n==0&&m==0) break;
printf("%d",ask(m)-ask(n-1));
}
}
//这这里纠结了好久,到底是去开区间还是闭区间,上线和下限怎么取,后来才发现下面那一个总是取不到,那就把下限加一就A了这一题
//这里的代码和上面不同的地方就是解决了区间的端点值本身就带有4的情况。
//这里再附上别人的代码,感觉写的也挺好的
- #include<iostream>
- #include<cstring>
- #include<queue>
- #include<cstdio>
- #include<cmath>
- #include<algorithm>
- #define N 55
- #define inf 1<<29
- #define MOD 9973
- #define LL long long
- #define eps 1e-7
- #define zero(a) fabs(a)<eps
- #define equal(a,b) zero(a-b)
- using namespace std;
- int dp[10][3];
- //dp[i][0],表示不存在不吉利数字
- //dp[i][1],表示不存在不吉利数字,且最高位为2
- //dp[i][2],表示存在不吉利数字
- void Init(){
- memset(dp,0,sizeof(dp));
- dp[0][0]=1;
- for(int i=1;i<=6;i++){
- dp[i][0]=dp[i-1][0]*9-dp[i-1][1]; //在最高位加上除了4之外的9个数字,但是可能在2之前加了6
- dp[i][1]=dp[i-1][0]; //就是在原先不含不吉利数字的最高位加2
- dp[i][2]=dp[i-1][2]*10+dp[i-1][0]+dp[i-1][1]; //在已经有不吉利数字最高位加任意数字,或者在无吉利数字前加4,或者在2前面加4
- }
- }
- int slove(int n){
- int len=0,bit[10];
- int tmp=n;
- while(n){
- bit[++len]=n%10;
- n/=10;
- }
- bit[len+1]=0;
- int ans=0;
- bool flag=false;
- for(int i=len;i;i--){
- ans+=dp[i-1][2]*bit[i];
- if(flag) //高位已经出现4或者62,后面的就随意
- ans+=dp[i-1][0]*bit[i];
- if(!flag&&bit[i]>4) //高位可能出现4的情况
- ans+=dp[i-1][0];
- if(!flag&&bit[i+1]==6&&bit[i]>2) //高位是6,后面一位可能出现2,这步debug了很久
- ans+=dp[i][1];
- if(!flag&&bit[i]>6) //高位可能出现6,要把后面最高位为2计入
- ans+=dp[i-1][1];
- if(bit[i]==4||(bit[i+1]==6&&bit[i]==2)) //高位已经出现4或者62
- flag=true;
- }
- return tmp-ans;
- }
- int main(){
- int l,r;
- Init();
- while(scanf("%d%d",&l,&r)!=EOF&&l+r)
- printf("%d\n",slove(r+1)-slove(l));
- return 0;
- }