• luogu P2183 [国家集训队]礼物


    LINK:礼物

    n个物品 m个人 每个人要分得wi 个物品 每个物品互异 分给每个人的物品不分顺序 求方案数。

    (n,pleq 1e9 mleq 5)

    方案数 那显然是 第一个人拿了w1件物品 方案为组合数 第二个人在第一个人之后拿 由于礼物不分顺序 所以这么做是正确的。

    方案数显然为乘法原理 组合数 是一个1e9的 模数也是1e9的 卢卡斯定理肯定不行。

    上扩展卢卡斯 考虑质因数分解p 最后采用中国剩余定理合并即可。

    这个模型出过好多遍了 一定要会写。

    //#include<bits/stdc++.h>
    #include<iostream>
    #include<cstring>
    #include<string>
    #include<ctime>
    #include<cctype>
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<deque>
    #include<list>
    #include<algorithm>
    #include<utility>
    #include<bitset>
    #include<set>
    #include<map>
    #include<iomanip>
    #define ll long long
    #define db double
    #define INF 1000000000
    #define ld long double
    #define pb push_back
    #define get(x) x=read()
    #define putl(x) printf("%lld
    ",x)
    #define gt(x) scanf("%d",&x)
    #define put(x) printf("%d
    ",x)
    #define rep(p,n,i) for(RE ll i=p;i<=n;++i)
    #define go(x) for(ll i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
    #define pii pair<ll,ll> 
    #define mk make_pair
    #define RE register
    #define ull unsigned long long
    #define ui unsigned ll
    using namespace std;
    char buf[1<<15],*fs,*ft;
    inline char getc()
    {
    	return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
    }
    inline ll read()
    {
    	RE ll x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    	return x*f;
    }
    const ll MAXN=20,maxn=200010;
    ll p,n,m,top;
    ll a[MAXN],sum,ans=1;
    ll w[MAXN],v[MAXN],x,y;
    ll ans1[MAXN],f[maxn];
    inline ll fj(ll x,ll xx,ll xxx,ll pp)
    {
    	ll cnt=0;
    	ll ww=pp;
    	while(ww<=x)
    	{
    		cnt+=x/ww;
    		cnt-=xx/ww;
    		cnt-=xxx/ww;
    		ww=ww*pp;
    	}
    	return cnt;
    }
    inline ll ksm(ll b,ll p,ll mod)
    {
    	ll cnt=1;
    	while(p)
    	{
    		if(p&1)cnt=cnt*b%mod;
    		b=b*b%mod;p=p>>1;
    	}
    	return cnt;
    }
    inline ll jc(ll x,ll pp,ll mod)
    {
    	if(x<=pp)return f[x];
    	ll ans=1;
    	ll w=x/mod;
    	ans=ksm(f[mod],w,mod);
    	ans=ans*f[x%mod]%mod;
    	return ans*jc(x/pp,pp,mod)%mod;
    }
    inline void exgcd(ll a,ll b)
    {
    	if(!b){x=1;y=0;return;}
    	exgcd(b,a%b);
    	ll z=x;x=y;y=z-a/b*y;
    }
    inline ll inv(ll w,ll mod)//x关于mod的逆元
    {
    	exgcd(w,mod);
    	return (x%mod+mod)%mod;
    }
    inline ll solve(ll a,ll b,ll pp,ll mod)
    {
    	ll k1=fj(a,b,a-b,pp);f[0]=1;
    	rep(1,mod,i)if(i%pp)f[i]=f[i-1]*i%mod;
    	else f[i]=f[i-1];
    	ll ans1,ans2,ans3;
    	ans1=jc(a,pp,mod);
    	ans2=jc(b,pp,mod);
    	ans3=jc(a-b,pp,mod);
    	return ans1*inv(ans2,mod)%mod*inv(ans3,mod)%mod*ksm(pp,k1,mod)%mod;
    }
    inline ll C(ll a,ll b)
    {
    	rep(1,top,i)ans1[i]=solve(a,b,w[i],v[i]);
    	ll cc=0;
    	rep(1,top,i)
    	{
    		ll M=p/v[i];
    		ll ww=inv(M,v[i]);
    		cc=(cc+M*ww%p*ans1[i]%p)%p;
    	}
    	return cc;
    }
    signed main()
    {
    	freopen("1.in","r",stdin);
    	get(p);get(n);get(m);
    	rep(1,m,i)get(a[i]),sum+=a[i];
    	if(sum>n){puts("Impossible");return 0;}
    	ll c=p;
    	for(ll i=2;i*i<=c;++i)
    		if(c%i==0)
    		{
    			w[++top]=i;v[top]=1;
    			while(c%i==0)c/=i,v[top]=v[top]*i;
    		}
    	if(c>1){w[++top]=c;v[top]=c;}
    	ll res=n;
    	rep(1,m,i)
    	{
    		ans=ans*C(res,a[i])%p;
    		res-=a[i];
    	}
    	putl(ans);
    	return 0;
    }
    

    注意有两点 一是 求阶乘的时候要记得提前预处理 这样可以加速 保证复杂度稳稳log^2 而是最后中国剩余定理合并也其实是求逆。

  • 相关阅读:
    spring cloud stream定时器 配置rabbitmq插件安装
    字母、单词统计
    动手动脑
    原码补码反码
    ATM
    开学第一课
    周进度报告8
    周进度报告7
    JavaWeb进度报告1
    周进度报告6
  • 原文地址:https://www.cnblogs.com/chdy/p/12535673.html
Copyright © 2020-2023  润新知