[国家集训队]礼物
题目背景
一年一度的圣诞节快要来到了。每年的圣诞节小 E 都会收到许多礼物,当然他也会送出许多礼物。不同的人物在小 E 心目中的重要性不同,在小 E 心中分量越重的人,收到的礼物会越多。
题目描述
小 E 从商店中购买了 n n n 件礼物,打算送给 m m m 个人,其中送给第 i i i 个人礼物数量为 w i w_i wi。请你帮忙计算出送礼物的方案数(两个方案被认为是不同的,当且仅当存在某个人在这两种方案中收到的礼物不同)。由于方案数可能会很大,你只需要输出模 P P P 后的结果。
输入格式
输入的第一行包含一个整数
P
P
P,表示模数。
第二行包含两个整数
n
n
n 和
m
m
m,分别表示小 E 从商店购买的礼物数和接受礼物的人数。
第
3
3
3 到第
(
m
+
2
)
(m + 2)
(m+2) 行,每行一个整数,第
(
i
+
2
)
(i + 2)
(i+2) 行的整数
w
i
w_i
wi 表示送给第
i
i
i 个人的礼物数量。
输出格式
若不存在可行方案,则输出 Impossible
,否则输出一个整数,表示模
P
P
P 后的方案数。
输入输出样例
样例输入1
100
4 2
1
2
样例输出1
12
样例输入2
100
2 2
1
2
样例输出2
Impossible
说明/提示
样例 1 解释
以 /
分割,/
前后分别表示送给第一个人和第二个人的礼物编号。
12
12
12 种方案详情如下:
1/2 3 1/2 4 1/3 4
2/1 3 2/1 4 2/3 4
3/1 2 3/1 4 3/2 4
4/1 2 4/1 3 4/2 3
数据规模与约定
设 P = ∏ i = 1 t p i c i P= \prod_{i=1}^t p_i^{c_i} P=∏i=1tpici, p i p_i pi 为质数。
对于 15 % 15\% 15% 的数据, n ≤ 15 n\leq 15 n≤15, m ≤ 5 m\leq 5 m≤5, p i c i ≤ 1 0 5 p_i^{c_i}\leq 10^5 pici≤105。
在剩下的 85 % 85\% 85% 数据中,约有 60 % 60\% 60% 的数据满足 t ≤ 2 t\leq 2 t≤2, c i = 1 c_i=1 ci=1, p i ≤ 1 0 5 p_i\leq 10^5 pi≤105,约有 30 % 30\% 30% 的数据满足 p i ≤ 200 p_i\leq 200 pi≤200。
对于 100 % 100\% 100% 的数据, 1 ≤ n ≤ 1 0 9 1\leq n\leq 10^9 1≤n≤109, 1 ≤ m ≤ 5 1\leq m\leq 5 1≤m≤5, 1 ≤ p i c i ≤ 1 0 5 1\leq p_i^{c_i}\leq 10^5 1≤pici≤105, 1 ≤ w i ≤ P ≤ 1 0 9 1\leq w_i \leq P\leq 10^9 1≤wi≤P≤109。
Code
#include <bits/stdc++.h>
#define int long long
using namespace std;
int w[10005];
int p, n, m, s, k = 1;
void exgcd(int a, int b, int &x, int &y)
{
if (b)
{
exgcd(b, a % b, y, x);
y -= a / b * x;
}
else
x = 1, y = 0;
}
int inv(int a, int p)
{
int x, y;
exgcd(a, p, x, y);
return (x + p) % p;
}
int qmi(int a, int b, int p)
{
int res = 1;
while (b)
{
if (b & 1)
res = res * a % p;
a = a * a % p;
b >>= 1;
}
return res;
}
int f(int a, int p, int k)
{
if (!a)
return 1;
int i, u = 1, v = 1;
for (i = 1; i < k; ++i)
if (i % p)
u = i * u % k;
for (i = a / k * k; i <= a; ++i)
if (i % p)
v = i % k * v % k;
return f(a / p, p, k) * qmi(u, a / k, k) % k * v % k;
}
int g(int a, int p)
{
if (a < p)
return 0;
return g(a / p, p) + a / p;
}
int h(int a, int b, int p, int k)
{
return f(a, p, k) * inv(f(b, p, k), k) % k * inv(f(a - b, p, k), k) % k * qmi(p, g(a, p) - g(b, p) - g(a - b, p), k) % k;
}
int exlucas(int a, int b, int p)
{
int i, j, k, l, s = 0;
for (i = 2, j = p; i * i <= j; ++i)
{
if (j % i)
continue;
for (k = i, j /= i; !(j % i); k *= i)
j /= i;
l = p / k;
s = (s + l * h(a, b, i, k) % p * inv(l, k)) % p;
}
if (j > 1)
{
l = p / j;
s = (s + l * h(a, b, j, j) % p * inv(l, j)) % p;
}
return s;
}
signed main()
{
cin >> p >> n >> m;
for (int i = 0; i < m; ++i)
{
cin >> w[i];
s += w[i];
}
if (s > n)
{
puts("Impossible");
return 0;
}
for (int i = 0; i < m; ++i)
{
k = k * exlucas(n, w[i], p) % p;
n -= w[i];
}
cout << k;
return 0;
}
广告
绿树公司 - 官方网站:https://wangping-lvshu.github.io/LvshuNew/
绿树智能 - 官方网站:https://wangping-lvshu.github.io/LvshuZhineng/
(现在使用,人人均可获得300元大奖)