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({1\over k})^{x_{deep}}+\sum({1\over k})^{y_{deep}}=1 \]

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

如果没有进位,那这个数小数部分数位之和\(S=m\),每进位一次\(S\)就要减去\(k-1\),所以\(S ≡ m ( m o d k − 1 ) S\equiv m\pmod {k-1}S≡m(modk−1)\),且\(S≤m\)
在某种操作方式下,如果把\(0\)\(1\)交换,那么\(1-v\)表示成的\(k\)进制数数位之和\(S'\) 就应该满足\(S'\equiv n\pmod {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\n");
		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\n",ans);
	return 0;
}
posted @ 2020-10-27 22:13  Mohogany  阅读(126)  评论(0编辑  收藏  举报