[AHOI2009]同类分布

题目大意:
  问在区间[l,r]内的正整数中,有多少数能被其个位数字之和整除。

思路:
  数位DP。
  极端情况下,每一位都是9,所以各位数字之和不超过9*18。(为了方便这里用了9*19)
  f[i][j][k][flag],表示DP到从左往右第i位时,各位数字之和为j,这个数字在模mod意义下为k。
  flag表示是否为边界情况。
  转移的时候枚举这一位上的数p。
  设当前位是cur,则转移方程为:
  f[i-1][j+p][(k*10+p)%mod][false]+=f[i][j][k][false];
  f[i-1][j+p][(k*10+p)%mod][false]+=f[i][j][k][true];(p<cur)
  f[i-1][j+p][(k*10+p)%mod][true]+=f[i][j][k][true];(p=cur)
  观察发现f的第1维只会同时用到两层,所以可以滚动数组。

 1 #include<cstdio>
 2 #include<cctype>
 3 #include<cstring>
 4 typedef unsigned long long qword;
 5 inline qword getint() {
 6     register char ch;
 7     while(!isdigit(ch=getchar()));
 8     register qword x=ch^'0';
 9     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
10     return x;
11 }
12 const qword pow[]={1ull,10ull,100ull,1000ull,10000ull,100000ull,1000000ull,10000000ull,100000000ull,1000000000ull,10000000000ull,100000000000ull,1000000000000ull,10000000000000ull,100000000000000ull,1000000000000000ull,10000000000000000ull,100000000000000000ull,1000000000000000000ull,10000000000000000000ull};
13 const int SUM=9*19;
14 qword f[2][SUM+1][SUM][2];
15 inline qword calc(const qword &n) {
16     const int len=__builtin_log10(n)+1;
17     qword ret=0;
18     for(register int mod=1;mod<=9*len;mod++) {
19         memset(f[len&1],0,sizeof f[len&1]);
20         f[len&1][0][0][true]=1;
21         for(register int i=len;i;i--) {
22             memset(f[!(i&1)],0,sizeof f[!(i&1)]);
23             const int cur=n%pow[i]/pow[i-1];
24             for(register int j=0;j<=mod;j++) {
25                 for(register int k=0;k<mod;k++) {
26                     for(register int p=0;p<10;p++) {
27                         if(j+p>mod) break;
28                         f[!(i&1)][j+p][((((k<<2)+k)<<1)+p)%mod][false]+=f[i&1][j][k][false];
29                         if(p<cur) f[!(i&1)][j+p][((((k<<2)+k)<<1)+p)%mod][false]+=f[i&1][j][k][true];
30                         if(p==cur) f[!(i&1)][j+p][((((k<<2)+k)<<1)+p)%mod][true]+=f[i&1][j][k][true];
31                     }
32                 }
33             }
34         }
35         ret+=f[0][mod][0][false]+f[0][mod][0][true];
36     }
37     return ret;
38 }
39 int main() {
40     const qword l=getint(),r=getint();
41     printf("%llu\n",calc(r)-calc(l-1));
42     return 0;
43 }

 

posted @ 2017-10-19 16:07  skylee03  阅读(210)  评论(1编辑  收藏  举报