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

Codeforces908G. New Year and Original Order

时间:2018-01-06 14:15:32      阅读:193      评论:0      收藏:0      [点我收藏+]

标签:++   using   枚举   name   display   clu   数位   log   排序   

给n<=10^700,问1到n中每个数在各数位排序后得到的数的和。答案膜1e9+7。

一看就是数位DP啦。。然而并没有什么思路。。

可以尝试统计n(i,j)表示数j在第i位的出现次数,知道了这个数组后就可以算答案了。可以枚举j,做一次DP,f(a,b,0/1)--考虑第a~n个数,有b个j,是否大于给定数字(因为当前大于给定数字不一定dp到前面的数就大于,所以当前大于给定数字的数也是有贡献的),等等光知道有多少j并不能确定第i位是否有j,行不通。

套路--k(i,j)表示第i位出现的>=j的数字的出现次数,则$n(i,j)=k(i,j)-k(i,j+1)$。现在f(a,b,0/1)中的b则表示有b个>=j的数,那么就可以递推了。用$X_a$表示给定数字第a位是谁:

1、$j>X_a$:$f(a,b,0)=(f(a+1,b,0)+f(a+1,b,1))*X_a+f(a+1,b,0),f(a,b,1)=(f(a+1,b-1,0)+f(a+1,b-1,1))*(10-j)+(f(a+1,b,0)+f(a+1,b,1))*(j-X_a-1)+f(a+1,b,1)$

2、$j<=X_a$:$f(a,b,0)=(f(a+1,b,0)+f(a+1,b,1))*j+(f(a+1,b-1,0)+f(a+1,b-1,1))*(X_a-j)+f(a+1,b-1,0),f(a,b,1)=(f(a+1,b-1,0)+f(a+1,b-1,1))*(10-X_a-1)+f(a+1,b-1,1)$。

还没完,边界条件:1、$j>X_n$:$f(n,0,0)=X_a+1,f(n,0,1)=j-X_a-1,f(n,1,1)=10-j,f(n,1,0)=0$。

2、$j<=X_n$:$f(n,0,0)=j,f(n,0,1)=0,f(n,1,0)=X_n-j+1,f(n,1,1)=10-X_n-1$。

这些加一减一、取等取不等的特别注意。把<和=归在一类是之前在草稿纸上推过发现可以合的。

然后就没了。注意检查膜。

技术分享图片
 1 //#include<iostream>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<cstdio>
 5 #include<map>
 6 //#include<bitset>
 7 #include<algorithm>
 8 //#include<cmath>
 9 using namespace std;
10 
11 int n;
12 #define maxn 711
13 char s[maxn];
14 const int mod=1e9+7;
15 int kk[maxn][12],f[maxn][maxn][2];
16 int main()
17 {
18     scanf("%s",s+1); n=strlen(s+1);
19     for (int j=0;j<=9;j++)
20     {
21         int num=s[n]-0;
22         if (j>num) {f[n][0][0]=num+1; f[n][1][0]=0; f[n][0][1]=j-num-1; f[n][1][1]=10-j;}
23         else {f[n][0][0]=j; f[n][1][0]=num-j+1; f[n][0][1]=0; f[n][1][1]=10-num-1;}
24         
25         for (int a=n-1;a;a--)
26         {
27             int num=s[a]-0;
28             if (j>num)
29             {
30                 f[a][0][0]=(1ll*(f[a+1][0][0]+f[a+1][0][1])*num+f[a+1][0][0])%mod;
31                 f[a][0][1]=(1ll*(f[a+1][0][0]+f[a+1][0][1])*(j-num-1)+f[a+1][0][1])%mod;
32                 for (int b=1,to=n-a+1;b<=to;b++)
33                 {
34                     f[a][b][0]=(1ll*(f[a+1][b][0]+f[a+1][b][1])*num+f[a+1][b][0])%mod;
35                     f[a][b][1]=(1ll*(f[a+1][b-1][0]+f[a+1][b-1][1])*(10-j)
36                     +1ll*(f[a+1][b][0]+f[a+1][b][1])*(j-num-1)+f[a+1][b][1])%mod;
37                 }
38             }
39             else
40             {
41                 f[a][0][0]=(1ll*(f[a+1][0][0]+f[a+1][0][1])*j)%mod;
42                 f[a][0][1]=0;
43                 for (int b=1,to=n-a+1;b<=to;b++)
44                 {
45                     f[a][b][0]=(1ll*(f[a+1][b][0]+f[a+1][b][1])*j
46                     +1ll*(f[a+1][b-1][0]+f[a+1][b-1][1])*(num-j)+f[a+1][b-1][0])%mod;
47                     f[a][b][1]=(1ll*(f[a+1][b-1][0]+f[a+1][b-1][1])*(10-num-1)+f[a+1][b-1][1])%mod;
48                 }
49             }
50         }
51         for (int i=n;i;i--) f[1][i][0]+=f[1][i+1][0],f[1][i][0]-=f[1][i][0]>=mod?mod:0,kk[i][j]=f[1][i][0];
52     }
53     int ans=0;
54     for (int i=1,ten=1;i<=n;i++)
55     {
56         for (int j=0;j<=9;j++)
57             ans+=1ll*(kk[i][j]-kk[i][j+1]+mod)*ten%mod*j%mod,
58             ans-=ans>=mod?mod:0,ans+=ans<0?mod:0;
59         ten=1ll*ten*10%mod;
60     }
61     printf("%d\n",ans);
62     return 0;
63 }
View Code

 

Codeforces908G. New Year and Original Order

标签:++   using   枚举   name   display   clu   数位   log   排序   

原文地址:https://www.cnblogs.com/Blue233333/p/8213650.html

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