礼物[Codevs1321]
2016-06-19 09:02
399 查看
题目描述 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
1004 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; }