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&mu; }
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

CF1279F New Year and Handle Change 题解

CF611H New Year and Forgotten Tree