CF908G New Year and Original Order
Posted flyfeather6
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF908G New Year and Original Order相关的知识,希望对你有一定的参考价值。
题意
给你一个数(n),另(S(x))表示(x)中各位数从小到大排序后的数,例如(S(120542)=12245)。
求(sum_{i=1}^n S(i))
(1 le n le 10^{700})
思路
首先肯定是一道数位dp
考虑将某位数的贡献(x imes 10^i)转化为(x)个(10^i)相加,设(dp[i][j][k][0/1])表示前(i)位中有(j)位的数字大于等于(k),是否等于(n)的方案数。
转移很显然(dp[i][j+(now ge k)][k][h &(now==n[i])]+=dp[i-1][j][k][h])
考虑计算答案,对于(dp[n][i][j][0/1])后(j)位的数都会产生贡献,加起来就是(underbrace{111cdots11}_{j ext{个}1})。那么对于某个数(x),当(1le i le x)的时候都会计算到一次,所以累计就是答案。
#include <bits/stdc++.h>
const int mu=1e9+7;
int dp[705][705][10][2],ans;
char s[705];
void reduce(int &x) { x+=x>>31μ }
int main(){
scanf("%s",s);
int l=strlen(s);
for (int i=1;i<=9;i++) dp[0][0][i][1]=1;
for (int i=1;i<=l;i++)
for (int j=0;j<i;j++)
for (int k=1;k<=9;k++)
for (int h=0;h<=1;h++){
int t=dp[i-1][j][k][h];
if (!t) continue;
for (int now=0;now<=9;now++){
if(h==1 && now>s[i-1]-‘0‘) break;
reduce(dp[i][j+(now>=k)][k][h&(now==s[i-1]-‘0‘)]+=t-mu);
}
}
for (int i=1;i<=9;i++){
for (int j=1,t=1;j<=l;j++,t=(t*10ll+1)%mu)
ans=(ans+1ll*t*(dp[l][j][i][0]+dp[l][j][i][1]))%mu;
}
printf("%d
",ans);
}
以上是关于CF908G New Year and Original Order的主要内容,如果未能解决你的问题,请参考以下文章
CF908GNew Year and Original Order 数位DP
CF 750C New Year and Rating(思维题)
CF1284E New Year and Castle Construction
CF1284E New Year and Castle Construction