【题解】准备

题目描述

Alien 的战舰不能搭载太多人,他需要在战舰上安装一些乘客客舱。

可以安装的客舱有 \(2p\) 个型号,分别能搭载 \(1\) 至 \(2p\) 个乘客,每种型号有且仅有一个。

为了方便搭载的过程,Alien 希望恰好安装 \(p\) 个乘客客舱,且可搭载的乘客数量和必须为 \(p\) 的倍数。

Alien 想知道共有几种方案?

输入格式

本题有多组数据。

第一行为数据组数 \(n\);

接下来 \(n\) 行每行包含一个 奇质数 \(p\)。

输出格式

对于每组数据输出一行,表示方案数。

数据范围

测试时间限制 \(500\ \mathrm{ms}\),空间限制 \(64\ \mathrm{MiB}\)。

  • 对于 \(30\%\) 的数据,\(n\le 10\),\(p\le 10\);
  • 对于 \(70\%\) 的数据,\(n\le 100\),\(p\le 30\);
  • 对于 \(100\%\) 的数据 \(0\le n\le 100\),\(3\le p\le 1000\)。

分析

这题一看就是个结论题。怎么推呢?

首先,我们将其抽象成一个数学问题:

给定集合 \(S=\left\{k|k\in \mathbb{N}^{+},1\le k\le 2p\right\}\)。

求出 \(|T|\),其中 \(T=\left\{S^\prime|S^\prime\subseteq S,\sum\limits_{x\in S^\prime}x\bmod{p}=0\right\}\)

嗯?怎么越来越不明所以了?

接下来,我们就考虑一下怎么解决。


首先,注意到前面 \(p\) 个数与后面 \(p\) 个数等价。

又 \(\forall S\in T\ \exists\, S_1,S_2\ S_1\cap S_2=\varnothing, S_1\subseteq \{k|k\in \mathbb{N}^{+},1\le k\le p\}, S_2\subseteq \{k|k\in \mathbb{N}^{+},p+1\le k\le 2p\}, S_1\cup S_2=S\)

即给定 \(S_1\),\(S_2\),能得到确定的 \(S\)。

接下来考虑如何搭配 \(S_1\) 和 \(S_2\)。


考虑给定 \(S_1\),有多少个 \(S_2\) 与其配对。

由于能够影响的只有余数,下面规定 \(f_i\) 为 \(S^\prime\subseteq \{k|k\in \mathbb{N}^+, 1\le k\le p\},\sum\limits_{x\in S^\prime}x\bmod{p}=i\) 的个数。

发现单独考虑并不容易,我们试图整体考虑。


注意到选择 \(f_i\) 时,选择的个数不会是 \(p\) 的倍数(全选和不选除外)。如果对于选的每一个数加一,那么就会产生另一种选择方案,其和的余数与原方案不同。

这样进行 \(p-1\) 次,我们就能得到一个关于 \(p\) 的最小剩余系。其中只有一个方案是合法的。

也就是说,除去全选和不选的方案,剩下的所有方案是平均分的。

于是,答案实际上就是 \(\dfrac{\dbinom{2p}{p}-2}{p}+2\)

最后再套上个高精度就能解决问题了。

Code

后来,我还是放弃了高精度……实在是太烦了。

#include <cstdio>
using namespace std;

typedef long long ll;

int main()
{
	int cas, n;
	ll ans;
	
	scanf("%d", &cas);
	while (cas--)
	{
		scanf("%d", &n);
		
		ans = 1;
		for (int i = n + 1; i <= 2 * n; i++)
			ans *= i;
		for (int i = 1; i <= n; i++)
			ans /= i;
		
		printf("%d\n", (ans - 2) / n + 2);
	}
	
	return 0;
}
posted @ 2020-04-06 10:10  5ab  阅读(145)  评论(0)    收藏  举报