怎么说,数位DP还是我的噩梦啊,细节太恐怖了。
但是这章感觉又和之前的学的数位DP有差异?(应该是用DP预处理降低时间复杂度,好劲啊,不过以前都是记忆化搜索的应该不会差多少)
poj3208 f[i][0~2]表示第i位,开头连续j个6的情况数,[3]表示魔鬼数的个数,这样可以方便得出区间内有多少魔鬼数,不停的试填到底即可。
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; LL f[20][4]; void initf() { f[0][0]=1; f[1][0]=9,f[1][1]=1,f[1][2]=f[1][3]=0; for(int i=2;i<=18;i++) { f[i][0]=9*(f[i-1][0]+f[i-1][1]+f[i-1][2]); f[i][1]=f[i-1][0]; f[i][2]=f[i-1][1]; f[i][3]=f[i-1][2]+10*f[i-1][3]; } } int main() { initf(); int T; scanf("%d",&T); while(T--) { int n; scanf("%d",&n); int w=1;while(f[w][3]<n)w++; int h6=0; for(int i=w;i>=1;i--) { for(int j=0;j<=9;j++) { LL cc=f[i-1][3]; if(j==6||h6==3) for(int k=max(3-h6-(j==6),0);k<=2;k++)cc+=f[i-1][k]; if(cc<n)n-=cc; else { if(h6<3) { if(j==6)h6++; else h6=0; } printf("%d",j); break; } } } printf(" "); } return 0; }
月之谜 这题找不到原题,但是lyd有数据。一个看似很复杂多余实则很重要的定义:f[i][j][k][p]表示位数为i,数字和为j,对k取模等于p的数的个数,k这一维无法省略,原因是当前面增加一个数字j改变对应的模数也改变。预处理完了,就一位一位枚举,只有上限边缘是无法确定值的,上限之下都可以通过预处理求得。
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; int MOD(int d,int mod){return (d%mod+mod)%mod;} int mi[20],f[13][110][110][110]; void initf() { mi[1]=1;for(int i=2;i<=10;i++)mi[i]=mi[i-1]*10; memset(f,0,sizeof(f)); for(int j=0;j<=9;j++) for(int k=1;k<=100;k++) f[1][j][k][j%k]++; for(int i=2,mi=10;i<=10;i++,mi*=10) { for(int m=0;m<=9;m++) for(int j=m;j<=100;j++) for(int k=1;k<=100;k++) for(int p=0;p<100;p++) f[i][j][k][p]+=f[i-1][j-m][k][MOD(p-mi*m,k)]; } } int maxw(int i) { int ret=0; while(i!=0)i/=10,ret++; return ret; } int getnum(int x,int i){return x/(mi[i])%10;} bool calc(int x) { int k=x,sum=0; while(k!=0)sum+=k%10,k/=10; if(sum==0)return 0; return x%sum==0; } int getmoon(int x,int sum,int pun,int i) { if(i==1) { int num=getnum(x,1),ret=0; for(int i=0;i<=num;i++) { x=x-x%10+i; if(calc(x)==true)ret++; } return ret; } int num=getnum(x,i),ret=0; for(int m=0;m<num;m++) { for(int j=max(1,sum+m);j<=100;j++) ret+=f[i-1][j-(sum+m)][j][MOD(-pun-mi[i]*m,j)]; } ret+=getmoon(x,sum+num,pun+mi[i]*num,i-1); return ret; } int main() { freopen("mystery.in","r",stdin); freopen("mystery.out","w",stdout); initf(); int L,R; while(scanf("%d%d",&L,&R)!=EOF) { if(L==1)printf("%d ",getmoon(R,0,0,maxw(R))); else printf("%d ",getmoon(R,0,0,maxw(R))-getmoon(L-1,0,0,maxw(L-1))); } return 0; }