BZOJ 2142 礼物(拓展Lucas,中国剩余定理)BZOJ修复工程

Posted 繁凡さん

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 2142 礼物(拓展Lucas,中国剩余定理)BZOJ修复工程相关的知识,希望对你有一定的参考价值。

整理的算法模板合集: ACM模板

点我看算法全家桶系列!!!

实际上是一个全新的精炼模板整合计划


题目链接

https://hydro.ac/d/bzoj/p/2142

hydro 的 BZOJ 修复工程 !(我也去领了一点题慢慢修着玩,这题就是我修的嘿嘿嘿)

题目描述

一年一度的圣诞节快要来到了。每年的圣诞节小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从商店购买的礼物数和接受礼物的人数;

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

输出格式

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

输入样例

100 
4 2 
1
2

输出样例

12

数据规模和约定

P = p 1 c 1 × p 2 c 2 × p 3 c 3 × ⋯ × p t c t P=p_1^{c_1} \\times p_2^{c_2} \\times p_3^{c_3} \\times \\cdots \\times p_t ^ {c_t} P=p1c1×p2c2×p3c3××ptct p i p_i pi 为质数。
对于 100 % 100\\% 100% 的数据, 1 ≤ n ≤ 1 0 9 1\\le n\\le 10^9 1n109 1 ≤ m ≤ 5 1\\le m\\le 5 1m5 1 ≤ p i c i ≤ 1 0 5 1\\le p_i^{c_i}\\le 10^5 1pici105

提示

【样例说明】

下面是对样例 1 1 1 的说明。
/ 分割,/ 前后分别表示送给第一个人和第二个人的礼物编号。 12 12 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 

Solution

一共 n n n 个礼物,第 1 1 1 个人需要 w 1 w_1 w1 个礼物,方案数为 ( w 1 n ) \\displaystyle {w_1 \\choose n} (nw1),然后对于第二个人,从剩下的 n − w 1 n-w_1 nw1 个礼物中选出 w 2 w_2 w2 个礼物送给第二个人,方案数为 ( w 2 n − w 1 ) \\displaystyle {w_2\\choose {n-w_1}} (nw1w2),一次类推,总方案数根据乘法原理显然为:

∏ i = 1 n ( w i n − ∑ j = 1 i w j ) m o d    p \\prod_{i = 1}^{n} {w_i\\choose \\displaystyle n-\\sum_{j=1}^{i}w_j}\\mod p i=1n(nj=1iwjwi)modp

考虑如何计算。

由于给定的模数 p p p 不是质数,所以我们需要用拓展Lucas定理计算,然后就是一个拓展lucas的模板题了…

关于拓展Lucas定理



Code

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int maxn = 1e4 + 6;
int n, m, s, t, ans;
int primes[maxn], cnt;
bool vis[maxn];
int v[maxn], M;
ll A, B;
int mod;
int w[maxn];
int r[maxn];

struct mods
{
	int c, p;
	ll pc;
}f[maxn];

ll qpow(ll a, ll b, ll mod)
{
	ll res = 1;
	while(b) {
		if(b & 1) res = res * a % mod;
		a = a * a % mod;
		b >>= 1;
	}
	return res;
}

ll exgcd(ll a, ll b, ll &x, ll &y)
{
	if(b == 0) {
		x = 1, y = 0;
		return a;
	}
	ll d = exgcd(b, a % b, x, y);
	ll z = x;
	x = y;
	y = z - y * (a / b);
	return d;
}

inline ll inv(ll a, ll p)
{
	ll x, y;
	exgcd(a, p, x, y);
	return (x + p) % p;
}

//计算 x! 中除掉 val = prime 后模 p 的值
inline ll cal(ll x, ll val, ll p)
{
	if(x == 0) return 1;
	ll res = 1;
	ll last = x % p;
	for (int i = 1; i <= p; ++ i) 
		if(i % val)	
			res = res * i % p;
	res = qpow(res, x / p, p);
	for (ll i = 1; i <= last; ++ i)
		if(i % val) 
			res = res * i % p;
	return res * cal(x / val, val, p) % p;
}
 
inline ll C(ll n, ll m, ll p, ll pc)
{
	if(m > n) return 0;
	ll k = 0;
	ll up = cal(n, p, pc);
	ll down1 = cal(m, p, pc);
	ll down2 = cal(n - m, p, pc);
	
	for (int i = n; i; i /= p) k += i / p;
	for (int i = m; i; i /= p) k -= i / p;
	for (int i = n - m; i; i /= p) k -= i / p; 
	
	return up * inv(down1, pc) % pc * inv(down2, pc) % pc * qpow(p, k, pc) % pc;
}

inline ll CRT(int cnt)
{
	ll m = mod, M[maxn] = {}, t[maxn] = {}, res = 0;
	for (int i = 1; i <= cnt; ++ i)
		M[i] = m / f[i].pc; 
	for (int i = 1; i <= cnt; ++ i) {
		ll y; 
		exgcd(M[i], f[i].pc, t[i], y); 
		res = (res + r[i] % m * M[i] % m * t[i] % m) % m; 
	}
	return (res % m + m) % m;
}

inline ll exlucas(ll A, ll B)
{
	memset(f, 0, sizeof f);
	memset(r, 0, sizeof r);
	int x = mod, cnt = 0;
	for (ll i = 2; i * i <= x; ++ i) {
		if(x % i == 0) {
			f[ ++ cnt].p = i;
			f[cnt].pc = 1;
			while(x % i == 0) {
				x /= i;
				f[cnt].c ++ ;
				f[cnt].pc *= i;
			} 
			r[cnt] = C(A, B, f[cnt].p, f[cnt].pc);
		}
	}
	if(x > 1) {
		f[ ++ cnt].p = x;
		f[cnt].c = 1;
		f[cnt].pc = x; 
		r以上是关于BZOJ 2142 礼物(拓展Lucas,中国剩余定理)BZOJ修复工程的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ2142 礼物

BZOJ 2142 礼物 数论

bzoj2142: 礼物

bzoj 2142: 礼物中国剩余定理+组合数学

[BZOJ2142]礼物(扩展Lucas)

BZOJ2142 礼物 扩展Lucas