• BZOJ2142 礼物 【扩展Lucas】


    题目

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

    输入格式

    输入的第一行包含一个正整数P,表示模;
    第二行包含两个整整数n和m,分别表示小E从商店购买的礼物数和接受礼物的人数;
    以下m行每行仅包含一个正整数wi,表示小E要送给第i个人的礼物数量。

    输出格式

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

    输入样例

    100

    4 2

    1

    2

    输出样例

    12

    提示

    【样例说明】

    下面是对样例1的说明。

    以“/”分割,“/”前后分别表示送给第一个人和第二个人的礼物编号。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=p1^c1 * p2^c2 * p3^c3 * … *pt ^ ct,pi为质数。

    对于100%的数据,1≤n≤109,1≤m≤5,1≤pi^ci≤10^5。

    题解

    式子很简单,记(sum[i])为w[i]前缀和:

    [ans = {n choose sum[m]} prodlimits {sum[m] - sum[i - 1] choose w[i]} ]

    重点在于计算(C_{n}^{m} mod P),其中(n,m le 10^9)(P = p_1^{k_1}*p_2^{k_2}*p_3^{k_3}.....),其中每一个(p_i^{k_i} le 10^5)

    扩展Lucas##

    对于质数(P le 10^5),我们可以用Lucas定理计算出

    [C_{n}^{m} = prodlimits_{i = 1} C_{lfloor frac{n}{P^{i - 1}} floor mod P^i}^{lfloor frac{m}{P^{i - 1}} floor mod P^i} ]

    但对于合数(P),Lucas定理就不再适用了
    于是我们使用中国剩余定理

    [left{ egin{array}{c} xequiv c_1pmod {m_1}\ xequiv c_2pmod {m_2} \ xequiv c_3pmod {m_3}\ ...\ xequiv c_kpmod {m_k} end{array} ight.]

    显然(x)就是答案,用中国剩余定理合并出(x)
    我们只需要快速计算(C_{n}^{m} mod p_i^{k_i})
    我们只需要快速计算(n! mod p_i^{k_i})
    因为((a + P) equiv a pmod P)

    [n! = prodlimits_{i = 1}^{n} i ]

    所以我们对(n)个数按(P)进行分组并提取出其中(p_i)的倍数,假使有(t)
    可以得出

    [n! = p_i^{t} * (prodlimits_{x = 1}^{p_i^{k_i}} x [x mod p_i e 0])^{frac{n}{p_i^{k_i}}} * (lfloor frac{n}{p_i} floor)! ]

    左边是(O(p_i^{k_i}))的,右边递归(lfloor frac{n}{p_i} floor)
    我们先提取出(n,m,n - m)(p_i),使其结果必定与(p_i)
    其中(n!)(p)的个数为(x=lfloor{nover p} floor+lfloor{nover p^2} floor+lfloor{nover p^3} floor+...)
    最后结合逆元计算出(frac{n!}{m!(n-m)!})再乘上(p_i^{sum t})就行了

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #define LL long long int
    #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
    using namespace std;
    const int maxn = 100005,maxm = 100005,INF = 1000000000;
    inline int read(){
    	int out = 0,flag = 1; char c = getchar();
    	while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
    	while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    	return out * flag;
    }
    LL sum;
    int md,n,m,a[10];
    int p[maxn],pk[maxn],pi,Ans[maxn];
    void Sp(){
    	int x = md;
    	for (int i = 2; i * i <= x; i++){
    		if (x % i == 0){
    			p[++pi] = i; pk[pi] = 1;
    			while (x % i == 0) x /= i,pk[pi] *= i;
    		}
    	}
    	if (x - 1) ++pi,p[pi] = pk[pi] = x;
    }
    int qpow(int a,int b,int md){
    	int ans = 1;
    	for (; b; b >>= 1,a = 1ll * a * a % md)
    		if (b & 1) ans = 1ll * ans * a % md;
    	return ans;
    }
    void exgcd(int a,int b,int& d,int& x,int& y){
    	if (!b) {d = a; x = 1; y = 0;}
    	else exgcd(b,a % b,d,y,x),y -= (a / b) * x;
    }
    int inv(int a,int P){
    	int d,x,y; exgcd(a,P,d,x,y);
    	return (x % P + P) % P;
    }
    int Fac(int n,int P,int Pi){
    	if (!n) return 1;
    	int ans = 1;
    	if (n / P){
    		for (int i = 2; i < P; i++)
    			if (i % Pi) ans = 1ll * ans * i % P;
    		ans = qpow(ans,n / P,P);
    	}
    	int E = n % P;
    	for (int i = 2; i <= E; i++)
    		if (i % Pi) ans = 1ll * ans * i % P;
    	return 1ll * ans * Fac(n / Pi,P,Pi) % P;
    }
    int C(int n,int m,int P,int pi){
    	if (m > n) return 0;
    	int a = Fac(n,P,pi),b = Fac(m,P,pi),c = Fac(n - m,P,pi),k = 0,ans;
    	for (int i = n; i; i /= pi) k += i / pi;
    	for (int i = m; i; i /= pi) k -= i / pi;
    	for (int i = n - m; i; i /= pi) k -= i / pi;
    	ans = 1ll * a * inv(b,P) % P * inv(c,P) % P * qpow(pi,k,P) % P;
    	return 1ll * ans * (md / P) % md * inv(md / P,P) % md;
    }
    int exlucas(int n,int m){
    	int ans = 0;
    	for (int i = 1; i <= pi; i++){
    		ans = (ans + C(n,m,pk[i],p[i])) % md;
    	}
    	return ans;
    }
    int main(){
    	md = read(); n = read(); m = read();
    	for (int i = 1; i <= m; i++){
    		sum += (a[i] = read());
    		if (sum > n) {puts("Impossible"); return 0;}
    	}
    	Sp();
    	int ans = exlucas(n,sum);
    	for (int i = 1; i <= m; i++)
    		ans = 1ll * ans * exlucas(sum,a[i]) % md,sum -= a[i];
    	printf("%d
    ",ans);
    	return 0;
    }
    
    
  • 相关阅读:
    想更改Github仓库中的某个文件结构
    记git一些基本用法
    剑指Offer-Python(16-20)
    剑指Offer-Python(11-15)
    初次使用flask
    Python的Cmd模块的简易运用学习
    SQL-全称量词查询
    线段树模板1
    OJ输入输出超时(C++)
    二叉查找树(BST)定义
  • 原文地址:https://www.cnblogs.com/Mychael/p/8970882.html
Copyright © 2020-2023  润新知