神奇的数位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的情况。

 

 

//这里再附上别人的代码,感觉写的也挺好的

  1. #include<iostream>  
  2. #include<cstring>  
  3. #include<queue>  
  4. #include<cstdio>  
  5. #include<cmath>  
  6. #include<algorithm>  
  7. #define N 55  
  8. #define inf 1<<29  
  9. #define MOD 9973  
  10. #define LL long long  
  11. #define eps 1e-7  
  12. #define zero(a) fabs(a)<eps  
  13. #define equal(a,b) zero(a-b)  
  14. using namespace std;  
  15. int dp[10][3];  
  16. //dp[i][0],表示不存在不吉利数字  
  17. //dp[i][1],表示不存在不吉利数字,且最高位为2  
  18. //dp[i][2],表示存在不吉利数字  
  19. void Init(){  
  20.     memset(dp,0,sizeof(dp));  
  21.     dp[0][0]=1;  
  22.     for(int i=1;i<=6;i++){  
  23.         dp[i][0]=dp[i-1][0]*9-dp[i-1][1];  //在最高位加上除了4之外的9个数字,但是可能在2之前加了6  
  24.         dp[i][1]=dp[i-1][0];    //就是在原先不含不吉利数字的最高位加2  
  25.         dp[i][2]=dp[i-1][2]*10+dp[i-1][0]+dp[i-1][1];  //在已经有不吉利数字最高位加任意数字,或者在无吉利数字前加4,或者在2前面加4  
  26.     }  
  27. }  
  28. int slove(int n){  
  29.     int len=0,bit[10];  
  30.     int tmp=n;  
  31.     while(n){  
  32.         bit[++len]=n%10;  
  33.         n/=10;  
  34.     }  
  35.     bit[len+1]=0;  
  36.     int ans=0;  
  37.     bool flag=false;  
  38.     for(int i=len;i;i--){  
  39.         ans+=dp[i-1][2]*bit[i];    
  40.         if(flag)   //高位已经出现4或者62,后面的就随意  
  41.             ans+=dp[i-1][0]*bit[i];  
  42.         if(!flag&&bit[i]>4)  //高位可能出现4的情况  
  43.             ans+=dp[i-1][0];  
  44.         if(!flag&&bit[i+1]==6&&bit[i]>2)  //高位是6,后面一位可能出现2,这步debug了很久  
  45.             ans+=dp[i][1];  
  46.         if(!flag&&bit[i]>6)  //高位可能出现6,要把后面最高位为2计入  
  47.             ans+=dp[i-1][1];  
  48.         if(bit[i]==4||(bit[i+1]==6&&bit[i]==2))  //高位已经出现4或者62  
  49.             flag=true;  
  50.     }  
  51.     return tmp-ans;  
  52. }  
  53. int main(){  
  54.     int l,r;  
  55.     Init();  
  56.     while(scanf("%d%d",&l,&r)!=EOF&&l+r)  
  57.         printf("%d\n",slove(r+1)-slove(l));  
  58.     return 0;  
  59. }  

 

posted @ 2017-04-09 19:50  OcahIBye  阅读(145)  评论(0编辑  收藏  举报