• 洛谷 P2183 [国家集训队]礼物)(扩展卢卡斯定理)


    [国家集训队]礼物

    题目背景

    一年一度的圣诞节快要来到了。每年的圣诞节小 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

    样例输入 #1

    100
    4 2
    1
    2
    
    • 1
    • 2
    • 3
    • 4

    样例输出 #1

    12
    
    • 1

    样例 #2

    样例输入 #2

    100
    2 2
    1
    2
    
    • 1
    • 2
    • 3
    • 4

    样例输出 #2

    Impossible
    
    • 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
    
    • 1
    • 2
    • 3
    • 4

    数据规模与约定

    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 n15 m ≤ 5 m\leq 5 m5 p i c i ≤ 1 0 5 p_i^{c_i}\leq 10^5 pici105

    在剩下的 85 % 85\% 85% 数据中,约有 60 % 60\% 60% 的数据满足 t ≤ 2 t\leq 2 t2 c i = 1 c_i=1 ci=1 p i ≤ 1 0 5 p_i\leq 10^5 pi105,约有 30 % 30\% 30% 的数据满足 p i ≤ 200 p_i\leq 200 pi200

    对于 100 % 100\% 100% 的数据, 1 ≤ n ≤ 1 0 9 1\leq n\leq 10^9 1n109 1 ≤ m ≤ 5 1\leq m\leq 5 1m5 1 ≤ p i c i ≤ 1 0 5 1\leq p_i^{c_i}\leq 10^5 1pici105 1 ≤ w i ≤ P ≤ 1 0 9 1\leq w_i \leq P\leq 10^9 1wiP109

    1、题目求若干个组合数对 p(不一定是素数)求模
    2、有几个组合数,就调用几次 扩展卢卡斯定理 模板
    
    • 1
    • 2
    #include 
    using namespace std;
    typedef long long ll;
    const int MaxN = 1000010;
    ll nn, mm, pp;
    
    ll exgcd(ll a, ll b, ll& x, ll& y)
    {
    	if(0 == b)
    	{
    		x = 1, y = 0;
    		return 0;
    	}
    	ll d, x1, y1;
    	d = exgcd(b, a % b, x1, y1);
    	x = y1, y = x1 - a / b * y1;
    	return d;
    }
    
    //计算 a^b mod p
    ll quick_pow(ll a, ll b, ll p)
    {
    	ll c = 1;
    	while(b)
    	{
    		if(b & 1)
    			c = (c * a) % p;
    		a = (a * a) % p;
    		b >>= 1;
    	}
    	return c;
    }
    
    // 计算逆元 ax = 1(mod p), 算出最小非负整数 x 
    ll inverse(ll a, ll p)	// gcd(a, p) = 1, 可以用好 exgcd 计算逆元x
    {
    	ll x, y;
    	exgcd(a, p, x, y);
    	return (x % p + p) % p;
    }
    
    // 递归 计算 n! mod p^k 的值
    ll fac(ll n, ll  p, ll pk)
    {
    	if(!n)
    		return 1;
    	ll ans = 1;
    	for(ll i = 1; i < pk; ++i)
    	{
    		if(i % p)
    			ans = (ans * i) % pk;
    	}
    	ans = quick_pow(ans, n / pk, pk); 
    	for(ll i = 1; i <= n % pk; ++i)		// 余下一部分,全部算上
    	{
    		if(i % p)
    			ans = (ans * i) % pk;
    	}
    	return ans * fac(n / p, p, pk) % pk;
    }
    
    // 计算 c[m][n]  mod p^k 
    ll combi(ll n, ll m, ll p, ll pk)
    {
    	if(n < m)
    		return 0;
    	ll  f1 = fac(n, p, pk), f2 = fac(m, p, pk), f3 = fac(n - m, p, pk);
    	ll t1 = n, t2 = m, t3 = n - m, cnt = 0;
    	for(; t1; t1 /= p)	
    		cnt += t1 / p;
    	for(; t2; t2 /= p)	
    		cnt -= t2 / p;
    	for(; t3; t3 /= p)	
    		cnt -= t3 / p;
    	return ((f1 * inverse(f2, pk) % pk) * inverse(f3, pk) % pk * quick_pow(p, cnt, pk)) % pk;
    }
    
    
    ll r[300], m[300];
    
    ll crt(ll n)
    {
    	ll M = 1, ans = 0;
    	for(ll i = 1; i <= n; ++i)
    		M *= m[i];
    	for(ll i = 1; i <= n; ++i)
    	{
    		ll c = M / m[i], x, y;
    		exgcd(c, m[i], x, y);
    		ans = (ans + r[i] * c * x % M) % M;
    	}
    	return (ans % M + M) % M;
    }
    
    ll exlucas(ll A, ll B, ll pp)
    {
    	memset(m, 0, sizeof m);
    	memset(r, 0, sizeof r);
    	ll tmp = pp;
    	int cnt = 0;
    	m[cnt] = 1;
    	for(ll i = 2; i * i <= pp; ++i)
    	{
    		if(tmp % i == 0)
    		{
    			m[++cnt] = 1;
    			while(tmp % i == 0)
    				tmp /= i, m[cnt] *= i;
    			r[cnt] = combi(A, B, i, m[cnt]);
    		}
    	}
    	if(tmp > 1)
    		m[++cnt] = tmp, r[cnt] = combi(A, B, tmp, m[cnt]);
    	return crt(cnt);
    }
    
    int main()
    {
    	ll person[10], sum = 0;
    	scanf("%lld%lld%lld", &pp, &nn, &mm);
    	for(ll i = 1; i <= mm; ++i)
    	{
    		scanf("%lld", &person[i]);
    		sum += person[i];
    	}
    	if(nn < sum)	// 不够分
    	{
    		printf("Impossible\n");
    		return 0;
    	}
    
    	ll mod = pp;
    	ll result = 1;
    	for(ll i = 1; i <= mm; ++i)
    	{
    		result = result * exlucas(nn, person[i], mod) % mod;
    		nn -= person[i];
    	}
    	printf("%lld\n", result);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
  • 相关阅读:
    微信内置浏览器调试和调试微信内的H5页面汇总(持续更新...)
    Linux的firewalld防火墙学习笔记220929
    zabbix5客户端安装和配置
    Mock工具之Moco使用
    银行招聘问题集锦
    React 防抖与节流用法
    nodejs 之npm包
    给设计小白推荐几款笔记本电脑与工具
    有氧运动与无氧运动的区别
    java基于springboot+vue的宠物商店领养挂失管理系统 element 前后端分离
  • 原文地址:https://blog.csdn.net/qq_38232157/article/details/127652714