码迷,mamicode.com
首页 > 其他好文 > 详细

LightOJ1068 Investigation(数位DP)

时间:2016-01-17 23:14:05      阅读:251      评论:0      收藏:0      [点我收藏+]

标签:

这题要求区间有多少个模K且各位数之和模K都等于0的数字。

注意到[1,231]这些数最大的各位数之和不会超过90左右,而如果K大于90那么模K的结果肯定不是0,因此K大于90就没有解。

考虑到数据规模,数据组数,这题状态这么表示:

dp[i][j][k]:位数为i模K结果为j且各位数之和模K结果为k的数字个数

然后就是转移方程,最后就是统计。。

统计部分好棘手。。。半乱搞下AC的。。还是对数位DP的这一部分太不熟悉了。

 1 #include<cstdio>
 2 #include<cstring>
 3 using namespace std;
 4 int K,d[11][90][90],pow[10]={1};
 5 int calu(int n){
 6     int res=0,pre=0,sum=0;
 7     for(int i=9; i>=0; --i){
 8         if(i==0) for(int j=0; j<=n/pow[i]%10; ++j) res+=d[i][(K-((pre*10+j)*pow[i])%K)%K][(K-(sum+j)%K)%K];
 9         else for(int j=0; j<n/pow[i]%10; ++j) res+=d[i][(K-((pre*10+j)*pow[i])%K)%K][(K-(sum+j)%K)%K];
10         pre=pre*10+n/pow[i]%10;
11         sum+=n/pow[i]%10;
12     }
13     return res;
14 }
15 int main(){
16     for(int i=1; i<10; ++i) pow[i]=pow[i-1]*10;
17     int t,a,b;
18     scanf("%d",&t);
19     for(int cse=1; cse<=t; ++cse){
20         scanf("%d%d%d",&a,&b,&K);
21         if(K>=90){
22             printf("Case %d: %d\n",cse,0);
23             continue; 
24         }
25         memset(d,0,sizeof(d));
26         d[0][0][0]=1;
27         for(int i=0; i<10; ++i) ++d[1][i%K][i%K];
28         for(int len=1; len<10; ++len){
29             for(int i=0; i<K; ++i){
30                 for(int j=0; j<K; ++j){
31                     if(d[len][i][j]==0) continue;
32                     for(int k=0; k<10; ++k) d[len+1][(i*10+k)%K][(j+k)%K]+=d[len][i][j];
33                 }
34             }
35         }
36         printf("Case %d: %d\n",cse,calu(b)-calu(a-1));
37     }
38     return 0;
39 }

 

LightOJ1068 Investigation(数位DP)

标签:

原文地址:http://www.cnblogs.com/WABoss/p/5137893.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!