数位统计型动态规划的基本写法

数位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

猜你喜欢

转载自www.cnblogs.com/aininot260/p/9466356.html