GMOJ 6833. 2020.10.24【NOIP提高A组】T3.justice

题目大意:

小M 是正义的代言人,他的实验室里有(n + m) 个活细胞,他正在用这些细胞进行生命进化的研究:
这(n + m) 个细胞初始有n 个细胞活性系数为x,其他的活性系数为y。由于生命
的演变具有随机性,每秒钟都会有k 个细胞合并起来,他们活性系数的平均数就是新
细胞的活性系数。小M 发现最后这(n + m) 个细胞总能合并成一个细胞。他想请你告
诉他,最后的这一个细胞有多少种可能出现的不同的活性系数?由于答案可能过大,请
输出答案对10^9 + 7 取模后的值。

这题我居然没调试就过了。

题解:

很容易可以发现,(x,y)的取值对答案没有影响,只有(n,m,k)会影响答案的值。
我们可以将整个合并过程想象成一棵k叉树,那么设每个点深度为(x_{deep})(y[deep]),权值都为(1),那么根节点的权值也为(1),就可以得到:

[sum({1over k})^{x_{deep}}+sum({1over k})^{y_{deep}}=1 ]

(sum({1over k})^{x_{deep}}) 可以看成是一个k进制小数。

如果没有进位,那这个数小数部分数位之和(S=m),每进位一次(S)就要减去(k-1),所以(S ≡ m ( m o d k − 1 ) Sequiv mpmod {k-1}S≡m(modk−1)),且(S≤m)
在某种操作方式下,如果把(0)(1)交换,那么(1-v)表示成的(k)进制数数位之和(S') 就应该满足(S'equiv npmod {k-1}S'且S ≤ n)
而此时的(S')是可以通过(S)计算出来的,若这个小数位数为(l),则(S ′ = ( l − 1 ) ∗ ( k − 1 ) + k − S)

这样就相当于要构造一个(k)进制小数,满足数位和为(S),(S)满足上面的限制,(S)对应的(S')也要满足上面的限制,求方案数。
简单(dp)求解。

#include<cstdio>
#include<algorithm>
#include<cstring>
#define N 3010
#define ll long long
#define mo 1000000007
using namespace std;
ll x,y,n,m,k,i,j,f[N*2][N][2],g[N][N],ans;
int main(){
	freopen("justice.in","r",stdin);
	freopen("justice.out","w",stdout);
	scanf("%lld%lld%lld%lld%lld",&n,&m,&k,&x,&y);
	if (x==y){
		printf("1
");
		return 0;
	}
	f[0][0][0]=1;
	for (i=1;i<=(n+m-1)/(k-1);i++){
		g[i-1][0]=(f[i-1][0][0]+f[i-1][0][1])%mo;
		for (j=1;j<=n;j++)
			g[i-1][j]=(g[i-1][j-1]+f[i-1][j][0]+f[i-1][j][1])%mo;
		for (j=0;j<=n;j++){
			if (j){
				if (j>=k) f[i][j][1]=(g[i-1][j-1]-g[i-1][j-k]+mo)%mo;
				else f[i][j][1]=g[i-1][j-1];
			}
			f[i][j][0]=(g[i-1][j]-g[i-1][j-1]+mo)%mo;
		}
	}
	for (i=1;i<=(n+m-1)/(k-1);i++)
		for (j=1;j<=n;j++)
			if (j%(k-1)==n%(k-1)&&(i*(k-1)-j+1)%(k-1)==m%(k-1)&&i*(k-1)-j+1<=m)
				ans=(ans+f[i][j][1])%mo;
	printf("%lld
",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/Mohogany/p/13887985.html