洛谷 P4999 烦人的数学作业(数位DP)

题目链接:https://www.luogu.com.cn/problem/P4999

 

和前面几道题的思路差不多。不难发现一个数每个数位上的和最大不过18*9,所以我们可以枚举数位和为1,和为2,和为3...然后看每一个有几个数,那么累计一下(和*个数)即为答案。

注意在mod的时候一些细节(比如减法中的mod),同时要多mod几下。

 

AC代码:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cmath>
 5 #include<cstring>
 6 using namespace std;
 7 typedef long long ll;
 8 const int mod=1e9+7;
 9 ll dp[20][200][200],ans[200];
10 int a[20];
11 ll DFS(int pos,int limit,int now,int cnt){
12     if(pos==0) return now==cnt;
13     if(!limit&&dp[pos][now][cnt]!=-1) return dp[pos][now][cnt];
14     int up=limit?a[pos]:9;
15     ll sum=0;
16     for(int i=0;i<=up;i++) sum+=DFS(pos-1,limit&&i==a[pos],now+i,cnt);
17     if(!limit) dp[pos][now][cnt]=sum;
18     return sum;
19 }
20 ll solve(ll x){
21     int len=0;
22     ll sum=0;
23     while(x){
24         a[++len]=x%10;
25         x/=10;
26     }
27     for(int i=1;i<=9*len;i++){
28         ans[i]=DFS(len,1,0,i);
29         sum=(sum+i*(ans[i]%mod))%mod;
30     }
31     return sum;
32 }
33 int main(){
34     int t;
35     ll n,m;
36     memset(dp,-1,sizeof(dp));
37     scanf("%d",&t);
38     while(t--){
39         scanf("%lld%lld",&n,&m);
40         printf("%lld\n",(solve(m)-solve(n-1)+mod)%mod);//
41     }
42     return 0;
43 }
AC代码

 

posted @ 2020-03-09 21:51  dfydn  阅读(172)  评论(0编辑  收藏  举报