CF908G New Year and Original Order

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));
}
路漫漫其修远兮,吾将上下而求索
原文地址:https://www.cnblogs.com/zzctommy/p/13859815.html