P4104 [HEOI2014]平衡

P4104 [HEOI2014]平衡

题意转换:

杠杆的平衡条件为 \(F1 \times L1 = F2 \times L2\)​, 因为橡皮的质量相等,所以平衡的条件为:左边橡皮到重心的距离和等于右边橡皮到重心的距离和,
题目也就转化为,在重心左边选\(i\)个数,再在右边选\((k-i)\)个点,到重心的距离和为\(x\)的方案数,也就是整数划分。

\(f[x][i]\)表示选i个数,使和为x的方案数(也就是将x划分为i个不同数的方案数)。
可以看做有i个盒子,考虑盒子里有1和无1的情况 。

有1:\(f[i-j][j-1]\) 无1:\(f[i-j][j]\)

那么\(f[i][j] = f[i-j][j-1] + f[i-j][j]\)

#include <cstdio>
#include <iostream>
#define orz cout << "AK IOI" <<"\n"

using namespace std;
const int maxk = 15;
const int maxn = 100010;

inline int read()
{
	int x = 0, f = 1;
	char ch = getchar();
	while (ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0';ch = getchar();}
	return x * f;
}
int T, n, k, p, f[maxn][maxk]; 
int main()
{
    //freopen(".in","r",stdin);
    //freopen(".out","w",stdout);
    T = read();
    while(T--)
    {
    	n = read(), k = read(), p = read();
    	int ans = 0;
    	f[0][0] = 1;
    	for(int i = 1; i <= n * k; i++)
		    for(int j = 1; j <= i && j <= k; j++)
		    {
		   	  f[i][j] = (f[i - j][j - 1] + f[i - j][j]) % p;
		   	  if(i >= n + 1) f[i][j] = (f[i][j] - f[i - n - 1][j - 1] + p) % p;
		    } 
		for(int i = 0; i <= k; i++)
		    for(int j = 0; j <= n * k; j++)
		    {
		   	  ans = (ans + f[j][i] * f[j][k - i] % p) % p;
		   	  if(i < k) ans = (ans + (f[j][i] * f[j][k - i - 1]) % p) % p; 
		    }
		printf("%d\n", ans);
	}
	return 0;
}

posted @ 2021-03-14 14:41  _程门立雪  阅读(50)  评论(0编辑  收藏  举报