HDOJ7060 Separated Number

题目链接

题意分析

考试的时候想到了按位分析 但是由于计算公式过于麻烦 所以就咕了

现在考虑一下按位分析怎么做

我们对于当前第\(i\)位可以做的贡献

假设分割之后它处在第\(j\)位上 那么他的贡献就是

\[d*10^j*num \]

\(d\)表示第\(i\)位的数字 而\(num\)表示这样之后的划分方案数

所以接下来我们的任务就是如何计算\(num\)

①\(i+j<n\)

如果\(i+j<n\) 的话 那么由于我们最后最多划分成\(k\)段 所以考虑插板法 答案就是

\[\sum_{m=0}^{k-2}C_{n-j-2}^{m} \]

②\(i+j=n\)

如果\(i+j=n\) 的话 那么由于我们最后最多划分成\(k\)段 所以考虑插板法 答案就是

\[\sum_{m=0}^{k-1}C_{n-j-1}^{m} \]

对于\(i+j=n\) 我们可以直接计算入答案中

而对于\(i+j<n\) 我们可以采用倒序的方式不断累加 从而计算

\[\sum_{j=0}^{n-i-1}num=\sum_{j=0}^{n-i-1}\sum_{m=0}^{k-2}C_{n-j-2}^{m} \]

那么关键问题就是如何计算\(\sum_{m=0}^{k-2}C_{n-j-2}^{m}\)以及\(\sum_{m=0}^{k-1}C_{n-j-1}^{m}\)

我们发现对应的格式是\(\sum_{i=0}^bC_a^i\)

所以 令

\[F(a,b)=\sum_{i=0}^bC_a^i \]

同时 ,由于

\[C_{n+1}^m=C_{n}^m+C_{n}^{m-1} \]

\[∴2F(a,b)=2C_a^0+2C_a^1+...+2C_a^b=C_a^0+C_{a+1}^1+...+C_{a+1}^{b}+C_{a}^{b}=C_{a+1}^0+C_{a+1}^1+...+C_{a+1}^{b}+C_{a}^{b}=F(a+1,b)+C_{a}^{b} \]

所以我们可以得到一个线性的递推公式出来

\[F(a,b)=2F(a-1,b)-C_{a-1}^{b} \]

这样的话就可以计算了

CODE:

#include<bits/stdc++.h>
#define M 1000611
using namespace std;
const long long mod=998244353;
int T,n,k;
char s[M];
long long ans,sum;
long long Pow[M],fac[M],inv[M];
long long Fa[M],Fb[M];
long long qpow(long long x,long long y)
{long long tmp=1;for(;y;y>>=1,x=x*x%mod) if(y&1) tmp=tmp*x%mod;return tmp;}
long long C(int x,int y)
{
	if(x<y) return 0;
	else return (fac[x]*inv[x-y]%mod)*inv[y]%mod;
}
int main()
{
//	freopen("data.in","r",stdin);	
	scanf("%d",&T);
	Pow[0]=fac[0]=inv[0]=1;
	for(int i=1;i<=1000000;++i) Pow[i]=Pow[i-1]*10%mod;
	for(int i=1;i<=1000000;++i) fac[i]=fac[i-1]*i%mod;
	inv[1000000]=qpow(fac[1000000],mod-2);
	for(int i=999999;i;--i) inv[i]=inv[i+1]*(i+1)%mod;
	
	while(T--)
	{
		scanf("%d%s",&k,s+1);n=strlen(s+1);
		sum=0;ans=0;
		Fa[0]=1;Fb[0]=(k>=2 ? 1:0); 
		for(int i=1;i<=n;++i)
		{
			Fa[i]=(2*Fa[i-1]%mod-C(i-1,k-1)+mod)%mod;
			Fb[i]=(2*Fb[i-1]%mod-C(i-1,k-2)+mod)%mod;
		}
//		for(int i=1;i<=n;++i) printf("%lld%c",Fa[i],(i==n ? '\n':' '));
//		for(int i=1;i<=n;++i) printf("%lld%c",Fb[i],(i==n ? '\n':' '));
		for(int i=n;i;--i)
		{
			if(i<n) sum=(sum+(Pow[n-i-1]*Fb[i-1]%mod))%mod;
			ans=(ans+((Pow[n-i]*Fa[i-1]%mod+sum)%mod)*(s[i]-'0')%mod)%mod;
		}
		printf("%lld\n",ans);
	} 
	return 0;
}
上一篇:用非递归的方式实现数组转树


下一篇:js es6 flat()和flatMap()