【题解】准备
题目描述
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;
}
本文来自博客园,作者 5ab,转载请注明链接哦 qwq
博客迁移啦,来看看新博客吧 -> https://5ab-juruo.oier.space/