第一次做数位dp,思路和大家的好像不一样。打算写完这个报告之后再好好看看别人的思路。
这里给出一个我看到的讲的一般方法:
比如hdoj2089这个题。
它用到的方法是:
设f[i][j] 表示以j开头的i位数中不含“4”和“62”的个数。
那么可以得到递推式:
for(i=2;i<=8;i++)
for(j=0;j<=9;j++)
for(k=0;k<=9;k++)
if(j!=4&&(!(j==6&&k==2)))
f[i][j]+=f[i-1][k];
这里我说的也不清楚。建议看看上面的那个链接,应该就明白了。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int f[11][11];
int n,m;
int num_n,num_m;
void init()
{
int i,j,k;
for(i=0;i<=9;i++)
{
if(i!=4)
f[1][i]=1;
}
for(i=2;i<=8;i++)
{
for(j=0;j<=9;j++)
{
for(k=0;k<=9;k++)
{
if(j!=4&&(!(j==6&&k==2)))
f[i][j]+=f[i-1][k];
}
}
}
}
int work(int num)
{
int i,j;
int digit[10];
int len=0,ans=0;
while(num)
{
digit[++len]=num%10;
num/=10;
}
digit[len+1]=0;
for(i=len;i;i--)
{
for(j=0;j<digit[i];j++)
{
if(j!=4&&(!(j==2&&digit[i+1]==6)))
ans+=f[i][j];
}
if(digit[i]==4||digit[i]==2&&digit[i+1]==6) break;//因为已经出现了4或者62,后面的数肯定是非法的了,所以直接退出就ok了。
}
return ans;
}
int main()
{
int i,j;
init();
/*for(i=1;i<=7;i++)
{
for(j=0;j<=9;j++)
{
cout<<"["<<i<<","<<j<<"]"<<"-->"<<f[i][j]<<" "<<endl;
}
cout<<endl;
}*/
while(scanf("%d%d",&n,&m))
{
if((n+m)==0) break;
num_m=work(m+1);
num_n=work(n);
//cout<<num_m<<" "<<num_n<<endl;
printf("%d\n",num_m-num_n);
}
return 0;
}
本着复用代码的原则,hdoj3555也用同样的方法,就可以求出。
但是这次求得是包含的情况。所以我需要求出不含的,然后减去就ok了。
这样显得有点笨,确实也是。不过也算是一种思路吧。
方程的含义和上面说的基本一样。条件转移稍微修改一下就可以了。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
__int64 f[25][11];
int T;
__int64 num_n,N;
void init()
{
int i,j,k;
for(i=0;i<=9;i++)
{
f[1][i]=1;
}
for(i=2;i<=25;i++)
{
for(j=0;j<=9;j++)
{
for(k=0;k<=9;k++)
{
if(!(j==4&&k==9))
f[i][j]+=f[i-1][k];
}
}
}
}
__int64 work(__int64 num)
{
int i=0,j;
int digit[30];
memset(digit,0,sizeof(digit));
int len=0;
while(num)
{
digit[++len]=num%10;
num/=10;
}
__int64 ans=0;
digit[1]+=1; //这里要+1,因为要包含N,所以要比它大1(但是不能N直接加1,可能会刚好超出__int64的正数范围).
for(i=1;i<=len;i++)
{
if(digit[i]>9)
{
digit[i]-=10;
digit[i+1]++;
}
}
if(digit[len+1]) len++;
for(i=len;i;i--)
{
for(j=0;j<digit[i];j++)
{
if(!(j==9&&digit[i+1]==4))
ans+=f[i][j];
}
if(digit[i]==9&&digit[i+1]==4) break;
}
return ans;
}
int main()
{
int i,j;
init();
scanf("%d",&T);
while(T--)
{
scanf("%I64d",&N);
num_n=work(N)-1;
num_n=N-num_n;
printf("%I64d\n",num_n);
}
return 0;
}