【AGC009E】Eternal Average

题目

题目链接:https://atcoder.jp/contests/agc009/tasks/agc009_e
黑板上有 (n)(0)(m)(1),我们每次选择 (k) 个数字将其擦除,然后把它们的平均数写上去,这样一直操作直到只剩下一个数字,问剩下的这个数字有多少种不同的情况。
答案对 (10^9+7) 取模。
(1 leq n,m leq 2000,2 leq k leq 2000)。保证 (n+m-1) 能被 (k-1) 整除。

思路

考虑这样一个过程:一开始有 (n) 个点权为 (0) 的点,(m) 个点权为 (1) 的点,然后每次操作选择任意 (k) 没有父亲的点,把他们的父亲设为一个全新的点,这个新点的权值为所选 (k) 个点的平均值。最后我们需要求根节点的权值的可能数量。
显然这个过程构成了一棵树,我们设第 (i) 个点权为 (1) 的点的深度为 (a_i),第 (i) 个点权为 (0) 的点的深度为 (b_i)(根节点深度为 (0)),那么我们需要求

[s=sum_{m}^{i=1}k^{-a_i} ]

有多少种可能。限制条件为

[sum_{m}^{i=1}k^{-a_i}+sum_{n}^{i=1}k^{-b_i}=1 ]

这个条件可以理解为把根节点看作 (1),然后每一个节点的权值为其父亲的 (frac{1}{k}),这样所有的叶子(也就是 (n+m) 个初始的点)的权值和等于 (1)。不难发现这个限制条件是充要的。
这个限制条件等价于 (1-s=sum_{n}^{i=1}k^{-b_i})
(s) 看作一个 (k) 进制数,其小数点后第 (i) 位为 (s_i),手玩一下进位的过程,一定有

[sum_{i}^{len}s_iequiv mpmod {k-1} ]

(1-s=sum_{n}^{i=1}k^{-b_i}) 同理可以得到

[len(k-1)-sum_{i}s_i+1equiv npmod {k-1} ]

并且 (s) 每一位之和不能超过 (m)(1-s) 每一位之和不能超过 (n)
考虑原题,小数点后最多只有 (frac{n+m-1}{k-1}leq n+m) 位,那么可以设 (f[i][j][0/1]) 表示现在考虑到第 (i) 位,前 (i) 位和为 (j),第 (i) 位为 (0) / 非 (0) 的方案数。
显然

[f[i][j][0]=f[i-1][j][0]+f[i-1][j][1] ]

[f[i][j][1]=sum^{j-1}_{l=max(0,j-k+1)}f[i-1][l][0]+f[i-1][l][1] ]

前缀和优化一下即可做到 (O(m(n+m)))

代码

#include <bits/stdc++.h>
using namespace std;

const int N=2010,MOD=1e9+7;
int n,m,k,ans,f[N*2][N][2],g[N];

int main()
{
	scanf("%d%d%d",&n,&m,&k);
	f[0][0][0]=1;
	for (int i=1;i<=n+m;i++)
	{
		g[0]=(f[i-1][0][0]+f[i-1][0][1])%MOD;
		for (int j=0;j<=m;j++)
		{
			if (j) g[j]=((g[j-1]+f[i-1][j][0])%MOD+f[i-1][j][1])%MOD;
			f[i][j][0]=(f[i-1][j][0]+f[i-1][j][1])%MOD;
			if (j>=k) f[i][j][1]=(g[j-1]-g[j-k])%MOD;
			if (j && j<k) f[i][j][1]=g[j-1];
			if (j%(k-1)==m%(k-1) && (i*(k-1)-j+1)%(k-1)==n%(k-1) && i*(k-1)-j+1<=n)
				ans=(ans+f[i][j][1])%MOD;
		}
	}
	printf("%d",(ans%MOD+MOD)%MOD);
	return 0;
}
原文地址:https://www.cnblogs.com/stoorz/p/14695109.html