• [BZOJ2142]礼物


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

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

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

    Sample Input
    100
    4 2
    1
    2

    Sample Output
    12

    HINT
    对于100%的数据,(1leqslant nleqslant 10^9,1leqslant mleqslant 5,1leqslant p_i^{c_i}leqslant 10^5)


    直接for循环?……没错,答案就为

    [Ans=sumlimits_{i=1}^minom{n-sumlimits_{j=1}^{i-1}w_j}{w_i} ]

    难点在于Ex_Lucas吧……

    /*program from Wolfycz*/
    #include<map>
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define inf 0x7f7f7f7f
    #define Fi first
    #define Se second
    #define MK std::make_pair
    typedef long long ll;
    typedef long double ld;
    typedef unsigned int ui;
    typedef std::map<int,int> mii;
    typedef unsigned long long ull;
    typedef std::pair<int,int> pii;
    inline char gc(){
    	static char buf[1000000],*p1=buf,*p2=buf;
    	return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
    }
    template<typename T>inline T frd(T x){
    	int f=1; char ch=gc();
    	for (;ch<'0'||ch>'9';ch=gc())	if (ch=='-')    f=-1;
    	for (;ch>='0'&&ch<='9';ch=gc())	x=(x<<1)+(x<<3)+ch-'0';
    	return x*f;
    }
    template<typename T>inline T read(T x){
    	int f=1;char ch=getchar();
    	for (;ch<'0'||ch>'9';ch=getchar())	if (ch=='-')	f=-1;
    	for (;ch>='0'&&ch<='9';ch=getchar())	x=(x<<1)+(x<<3)+ch-'0';
    	return x*f;
    }
    inline void print(int x){
    	if (x<0)    putchar('-'),x=-x;
    	if (x>9)	print(x/10);
    	putchar(x%10+'0');
    }
    template<typename T>inline T min(T x,T y){return x<y?x:y;}
    template<typename T>inline T max(T x,T y){return x>y?x:y;}
    template<typename T>inline T swap(T &x,T &y){T t=x; x=y,y=t;}
    namespace Math{
    	mii f[10];
    	int P[10],C[10],V[10],tot,SP;
    	void prepare(int p){
    		SP=p;
    		for (int i=2;i*i<=p;i++){
    			if (p%i)	continue;
    			P[++tot]=i,V[tot]=1;
    			while (p%i==0)	p/=i,V[tot]*=i,C[tot]++;
    			f[tot].insert(mii::value_type(0,1));
    			for (int j=1;j<=V[tot];j++)	f[tot].insert(mii::value_type(j,1ll*f[tot].find(j-1)->Se*(j%i?j:1)%V[tot]));
    		}
    		if (p!=1){
    			f[++tot].insert(mii::value_type(0,1));
    			P[tot]=V[tot]=p,C[tot]=1;
    			for (int j=1;j<=V[tot];j++)	f[tot].insert(mii::value_type(j,1ll*f[tot].find(j-1)->Se*(j%p?j:1)%V[tot]));
    		}
    	}
    	int mlt(int a,int b,int p){
    		int res=1;
    		for (;b;b>>=1,a=1ll*a*a%p)	if (b&1)	res=1ll*res*a%p;
    		return res;
    	}
    	int gcd(int a,int b){return !b?a:gcd(b,a%b);}
    	void exgcd(int a,int b,int &x,int &y){
    		if (!b){x=1,y=0;return;}
    		exgcd(b,a%b,x,y);
    		int t=x; x=y,y=t-a/b*y;
    	}
    	int Ex_GCD(int a,int b,int c){
    		int d=gcd(a,b),x,y;
    		if (c%d)	return -1;
    		a/=d,b/=d,c/=d;
    		exgcd(a,b,x,y);
    		x=(1ll*x*c%b+b)%b;
    		return x;
    	}
    	pii work(int n,int i){
    		if (n<=1)	return MK(1,0);
    		int res=1ll*mlt(f[i].find(V[i])->Se,n/V[i],V[i])*f[i].find(n%V[i])->Se%V[i],cnt;
    		pii tmp=work(cnt=n/P[i],i);
    		return MK(1ll*res*tmp.Fi%V[i],tmp.Se+cnt);
    	}
    	int calc(int n,int m,int i){
    		pii tmp; int res=1,cnt=0;
    		tmp=work(n,i); cnt+=tmp.Se;
    		res=1ll*res*tmp.Fi%V[i];
    		
    		tmp=work(m,i); cnt-=tmp.Se;
    		res=1ll*res*Ex_GCD(tmp.Fi,V[i],1)%V[i];
    		
    		tmp=work(n-m,i); cnt-=tmp.Se;
    		res=1ll*res*Ex_GCD(tmp.Fi,V[i],1)%V[i];
    		
    		return cnt<C[i]?1ll*res*mlt(P[i],cnt,V[i])%V[i]:0;
    	}
    	int Ex_C(int n,int m){
    		if (n<m)	return -1;
    		if (tot==1)	return Ex_GCD(1,V[1],calc(n,m,1));
    		int Ans=0;
    		for (int i=1;i<=tot;i++)	Ans=(Ans+1ll*Ex_GCD(SP/V[i],V[i],1)*(SP/V[i])%SP*calc(n,m,i)%SP)%SP;
    		return Ans;
    	}
    }
    using namespace Math;
    int main(){
    	int p=read(0),n=read(0),m=read(0),Ans=1;
    	prepare(p); int sum=0;
    	for (int i=1;i<=m;i++){
    		int x=read(0),res=Ex_C(n-sum,x);
    		if (!~res){
    			printf("Impossible
    ");
    			return 0;
    		}
    		Ans=1ll*Ans*res%p,sum+=x;
    	}
    	printf("%d
    ",Ans);
    	return 0;
    }
    
  • 相关阅读:
    VSFTP日志文件详解
    RocketMQ多master多salve集群搭建
    数据持久化之bind Mounting
    数据持久化之Data Volume
    gitLab 分支保护设置
    docker容器的端口映射
    docker命令之link
    NFS客户端挂载失败之authenticated unmount request from
    docke网络之bridge、host、none
    docke通信之Linux 网络命名空间
  • 原文地址:https://www.cnblogs.com/Wolfycz/p/10630632.html
Copyright © 2020-2023  润新知