您的位置:首页 > 其它

礼物[Codevs1321]

2016-06-19 09:02 351 查看

题目描述 Description

一年一度的圣诞节快要来到了。每年的圣诞节小E都会收到许多礼物,当然他也会送出许多礼物。不同的人物在小E心目中的重要性不同,在小E心中分量越重的人,收到的礼物会越多。小E从商店中购买了 n 件礼物,打算送给 m 个人,其中送给第 i 个人礼物数量为 wi 。请你帮忙计算出送礼物的方案数(两个方案被认为是不同的,当且仅当存在某个人在这两种方案中收到的礼物不同)。由于方案数可能会很大,你只需要输出模 p 后的结果。

输入描述 Input Description

输入的第一行包含一个正整数 P ,表示模;

第二行包含两个整整数 n 和 m ,分别表示小E从商店购买的礼物数和接受礼物的人数;

以下 m 行每行仅包含一个正整数 wi ,表示小E要送给第 i 个人的礼物数量。

输出描述 Output Description

若不存在可行方案,则输出 Impossible ,否则输出一个整数,表示模 P 后的方案数。

样例输入 Sample Input

100

4 2

1

2

样例输出 Sample Output

12

数据范围及提示 Data Size & Hint

以“/”分割,“/”前后分别表示送给第一个人和第二个人的礼物编号。 12 种方案详情如下:

1/23 1/24 1/34

2/13 2/14 2/34

3/12 3/14 3/24

4/12 4/13 4/23

数据规模

设 P=∏ti=1pcii, pi 为质数。

对于 15% 的数据, n≤15,m≤5,pcii≤105;

在剩下的 85% 数据中,约有 60% 的数据满足 t≤2,ci=1,pi≤105 ,约有 30% 的数据满足 pi≤200。

对于 100% 的数据, 1≤n≤109,1≤m≤5,1≤pcii≤105。

分析 I Think

显然 , ans=∏mi=1Cwin−∑i−1j=1wjmod P,当 ∑mi=1wi<n 时无解。令 x=wi,y=n−∑i−1j=1wj,这道题就只要能求出 Cxymod P 大工就告成了

解 Cxymod P 就相当于是解 t 个 r≡Cxy(mod pcii) 的同余方程组,用孙子定理即可。但我们需要求出 Cxy(mod pcii)

Cxymod pcii=y!x!(y−x)!。

这时我们需要将 y! 进行处理,使其等于 a(mod P)∗pbi 的形式,我们将 y 分成 ⌊dpcii⌋+1 段,其中前 ⌊dpcii⌋ 中不含 pi 的数之积取余 P 是一样的,而包含 pi 的部分可以继续递归下去,最后再把第 ⌊dpcii⌋+1 段乘上去即可

代码 Code

#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>

#define REP(i, l, r) for(LL i=(l); i!=(r); ++i)
#define FOR(i, l, r) for(LL i=(l); i<=(r); ++i)

typedef long long LL;

template<class T>T Min(const T &a, const T &b) {return a < b ? a : b;}
template<class T>T Max(const T &a, const T &b) {return a > b ? a : b;}
template<class T>bool Chkmin(T &a, const T &b) {return a > b ? a=b, 1 : 0;}
template<class T>bool Chkmax(T &a, const T &b) {return a < b ? a=b, 1 : 0;}

const int SN = 20;

LL prime[SN], pk[SN], ni[SN]; // p[i] & p[i]^a[i] & (p/(pk[i]))^(-1)(mod pk[i])
LL p, n, m, a[SN]; // input
LL c[SN]; // Merge

LL GetPrime(); // Get prime, pk, nk
LL ExGcd(LL, LL, LL &, LL &);
LL Get(LL, LL, LL); // do C(a,b) mod c
void Factor(LL, LL, LL &, LL &); // a! mod pk[b] = c * prime[b]^d
LL Power(LL, LL, LL);
LL Merge();  // Chinese Remineded LAD

int main() {

LL x, y, z, ans=1;

scanf("%lld%lld%lld", &p, &m, &n), GetPrime();
REP(i, 0, n) {
scanf("%lld", &x);
if(m < x) {puts("Impossible"); return 0;}
FOR(j, 1, prime[0]) c[j] = Get(x, m, j);
ans = ans*Merge()%p, m -= x;
}
printf("%lld\n", ans);

return 0;

}

LL GetPrime() {
LL x, y, tmp = p;
FOR(i, 2, sqrt(tmp)) if(tmp%i == 0) {
prime[++prime[0]]=i, pk[prime[0]]=1;
while(tmp%i == 0) pk[prime[0]]*=i, tmp/=i;
}
if(tmp != 1) ++prime[0], prime[prime[0]]=pk[prime[0]]=tmp;
FOR(i, 1, prime[0])
ExGcd(p/pk[i], pk[i], x, y), ni[i]=(x%pk[i]+pk[i])%pk[i];
}

LL ExGcd(LL a, LL b, LL &x, LL &y) {
if(!b) {x=1, y=0; return a;}
LL z = ExGcd(b, a%b, y, x);
return y-=(a/b)*x, z;
}

LL Get(LL a, LL b, LL r) {
LL mod = pk[r];
LL x1, x2, x3, y1, y2, y3, x, y;
Factor(b, r, x1, y1), Factor(a, r, x2, y2), Factor(b-a, r, x3, y3);
ExGcd(x2*x3%mod, mod, x, y), x = (x%mod+mod)%mod;
return x*x1%mod*Power(prime[r], y1-y2-y3, mod)%mod;
}

void Factor(LL a, LL r, LL &x, LL &y) {
LL x1, y1, mod=pk[r], x2, x3;
if(a <= prime[r]) {
y = a==prime[r];
FOR(i, x=1, a-y) x = x*i%mod;
return ;
}
Factor(y=a/prime[r], r, x1, y1), y += y1;
REP(i, x2=1, pk[r]) if(i%prime[r]) x2 = x2*i%mod;
FOR(i, x3=1, a%pk[r]) if(i%prime[r]) x3 = x3*i%mod;
x = Power(x2, a/pk[r], mod) * x3 % mod * x1 % mod;
}

LL Power(LL x, LL y, LL mod) {
LL ans = 1;
while(y) {
if(y & 1) ans = ans*x%mod;
x = x*x%mod, y >>= 1;
}
return ans;
}

LL Merge() {
LL ans = 0;
FOR(i, 1, prime[0]) ans = (ans+c[i]*ni[i]%p*(p/pk[i])%p)%p;
return ans;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  数学