码迷,mamicode.com
首页 > 其他好文 > 详细

CF908G New Year and Original Order

时间:2020-07-02 21:54:30      阅读:59      评论:0      收藏:0      [点我收藏+]

标签:等于   clu   转化   sum   problem   math   text   ++   %s   

题意

给你一个数\(n\),另\(S(x)\)表示\(x\)中各位数从小到大排序后的数,例如\(S(120542)=12245\)
\(\sum_{i=1}^n S(i)\)

\(1 \le n \le 10^{700}\)

传送门

思路

首先肯定是一道数位dp

考虑将某位数的贡献\(x\times 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{111\cdots11}_{j\text{个}1}\)。那么对于某个数\(x\),当\(1\le 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\n",ans);
}

CF908G New Year and Original Order

标签:等于   clu   转化   sum   problem   math   text   ++   %s   

原文地址:https://www.cnblogs.com/flyfeather6/p/13226864.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!