Loading

CF908G New Year and Original Order

CF908G New Year and Original Order

题意:给 \(n<=10^{700}\) ,问 \(1\)\(n\) 中每个数在各数位排序后得到的数的和,答案对 \(10^9+7\) 取模。

太久没写数位dp了,调到自闭。感谢 \(\color{black}{\texttt{z}}\color{red}{\texttt{houakngyang}}\) 耐心的指导

每一个数排序以后可以拆成 \(9\) 个形如 \(111\cdots1\) 数的和(比如 \(223=111+111+1+0+0+\cdots+0\)

对于每一个 \(1\le i \le 9\) ,当这一位的值不小于 \(i\) 的时候,\(i\) 所对应的 \(1\) 串长度会增加 \(1\)

考虑数位dp出 “对于某一个 \(i\) 恰有 \(j\)\(1\)”的数量

状态开 \(4\) 维,分别表示:在第几位,是否顶到上界,还需要几个不小于 \(i\) 的值,\(i\)

就可以转移了

状态总数是 \(n^2*10\) 的,可以通过

考虑枚举 \(i,j\) 计算答案

\(ans=\sum\limits_{j=1}^{9}\sum\limits_{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\n",solve(s));
}
posted @ 2020-10-22 17:57  zzctommy  阅读(84)  评论(0编辑  收藏  举报