数位dp一般应用于:
求出在给定区间[A,B]内,符合条件P(i)的数i的个数
条件P(i)一般与数的大小无关,而与 数的组成 有关
例题是一道BZOJ1833,让求出区间所有整数每个数字出现的次数
递推出f[i][j][k]表示长度为i开头j的所有数字中k的个数
这个东西让我想起了大模拟,高精度
1 #include<cstdio> 2 using namespace std; 3 //a,b 10^12 4 long long a,b; 5 long long t[25]; 6 struct Data{long long a[15];}f[25][15]; 7 Data operator +(Data a,Data b) 8 { 9 Data t; 10 for(int k=0;k<=9;k++) 11 t.a[k]=a.a[k]+b.a[k]; 12 return t; 13 } 14 inline long long read() 15 { 16 long long x=0,f=1;char ch=getchar(); 17 while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();} 18 while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();} 19 return x*f; 20 } 21 Data cal(long long x) 22 { 23 Data ans;for(int i=0;i<=9;i++) ans.a[i]=0; 24 if(x==0) 25 { 26 ans.a[0]=1; 27 return ans; 28 } 29 int len=15; 30 while(t[len]>x) len--; 31 for(int i=1;i<len;i++) 32 for(int j=1;j<=9;j++) 33 ans=ans+f[i][j]; 34 ans.a[0]++; 35 int cur=x/t[len]; 36 for(int i=1;i<cur;i++) ans=ans+f[len][i]; 37 x%=t[len]; 38 ans.a[cur]+=x+1; 39 for(int i=len-1;i;i--) 40 { 41 cur=x/t[i]; 42 for(int j=0;j<cur;j++) 43 ans=ans+f[i][j]; 44 x%=t[i]; 45 ans.a[cur]+=x+1; 46 } 47 return ans; 48 } 49 int main() 50 { 51 t[1]=1; 52 for(int i=2;i<=15;i++) t[i]=t[i-1]*10; 53 for(int i=0;i<=9;i++) f[1][i].a[i]=1; 54 //初始化 55 //递推出f[i][j][k]表示长度为i开头j的所有数字中k的个数 56 for(int i=2;i<=12;i++) //数字长度 57 for(int x=0;x<=9;x++) 58 for(int y=0;y<=9;y++) 59 { 60 f[i][y]=f[i][y]+f[i-1][x]; 61 f[i][y].a[y]+=t[i-1]; 62 } 63 a=read();b=read(); 64 Data t1=cal(b),t2=cal(a-1); 65 for(int i=0;i<=9;i++) 66 { 67 printf("%lld",t1.a[i]-t2.a[i]); 68 if(i!=9) printf(" "); 69 } 70 return 0; 71 }
cal函数就是计算从0到当前数中每一个数字出现的次数,对a和b分别求然后作差就好了
挺恶心的一种dp