CF908G New Year and Original Order
题意:给 (n<=10^{700}) ,问 (1) 到 (n) 中每个数在各数位排序后得到的数的和,答案对 (10^9+7) 取模。
太久没写数位dp了,调到自闭。感谢 (color{black}{ exttt{z}}color{red}{ exttt{houakngyang}}) 耐心的指导
每一个数排序以后可以拆成 (9) 个形如 (111cdots1) 数的和(比如 (223=111+111+1+0+0+cdots+0))
对于每一个 (1le i le 9) ,当这一位的值不小于 (i) 的时候,(i) 所对应的 (1) 串长度会增加 (1)
考虑数位dp出 “对于某一个 (i) 恰有 (j) 个 (1)”的数量
状态开 (4) 维,分别表示:在第几位,是否顶到上界,还需要几个不小于 (i) 的值,(i)
就可以转移了
状态总数是 (n^2*10) 的,可以通过
考虑枚举 (i,j) 计算答案
(ans=sumlimits_{j=1}^{9}sumlimits_{i=1}^{|n|}dp[i][j]*f[j])
(f[j]) 表示有 (j) 个 (1) 的串的值
我忘记开-Wall导致一个变量没用调了一下午
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef double db;
#define x first
#define y second
#define sz(v) (int)v.size()
#define pb(x) push_back(x)
#define mkp(x,y) make_pair(x,y)
inline int read(){
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=0;c=getchar();}
while(isdigit(c))x=x*10+c-'0',c=getchar();
return f?x:-x;
}
#define N 705
#define mod 1000000007
char s[N];
int d[N],dp[N][N][10];
void fmod(int&x){x-=mod,x+=x>>31&mod;}
int qpow(int n,int k){int res=1;for(;k;k>>=1,n=1ll*n*n%mod)if(k&1)res=1ll*n*res%mod;return res;}
int dfs(int pos,int limit,int sum,int low){
if(!pos)return !sum;
if(!limit&&~dp[pos][sum][low])return dp[pos][sum][low];
int res=0,up=limit?d[pos]:9;
for(int i=0;i<=up;++i)fmod(res+=dfs(pos-1,limit&&i==up,sum-(i>=low),low));
if(!limit)dp[pos][sum][low]=res;
return res;
}
int solve(char*s){
int res=0;
d[0]=0;int n=strlen(s+1);
for(int i=1,j=n;i<=n;++i,--j)d[j]=s[i]-'0';
for(int i=1;i<=9;++i)
for(int j=1,now=1;j<=n;++j,now=(10ll*now+1)%mod)
fmod(res+=1ll*dfs(n,1,j,i)*now%mod);
return res;
}
signed main(){
memset(dp,-1,sizeof(dp));
scanf("%s",s+1);
printf("%d
",solve(s));
}