[国家集训队]礼物,洛谷P2183,扩展Lucas

正题

      题目链接点这里

      首先,很明显我们发现答案就是\prod_{i=1}^m C(n-\sum_{j=1}^{i-1}w_j,w_i)

      假如wi加在一起没有n那么大,那么就输出Impossible。

      但是现在P又不给出来,没有好的性质,就只能用扩展Lucas来做了,而且它还保证质因子不超过1e5,这使我们枚举剩下许多时间。

#include
#include
#include
#include
using namespace std;

long long n,p;
int m;

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

long long inv(long long a,long long b){
    long long x,y;
    exgcd(a,b,x,y);
    x=(x%b+b)%b;
    if(x==0) return b;
    return x;
}

long long ksm(long long x,long long t,long long mod){
    long long tot=1;
    while(t>0){
        if(t%2==1) (tot*=x)%=mod;
        (x*=x)%=mod;
        t/=2;
    }
    return tot;
}

long long calc(long long x,long long pi,long long pk){
    if(x==0) return 1;
    long long ans=1;
    if(x/pk!=0){
        for(int i=2;i<=pk;i++) 
            if(i%pi!=0) (ans*=i)%=pk;
        ans=ksm(ans,x/pk,pk);
    }
    for(int i=2;i<=x%pk;i++) if(i%pi!=0)(ans*=i)%=pk;
    return ans*calc(x/pi,pi,pk)%pk;
}

long long C(long long n,long long m,long long pi,long long pk){
    long long a=calc(n,pi,pk),b=calc(n-m,pi,pk),c=calc(m,pi,pk);
    long long k=0;
    for(long long i=n;i!=0;i/=pi) k+=i/pi;
    for(long long i=n-m;i!=0;i/=pi) k-=i/pi;
    for(long long i=m;i!=0;i/=pi) k-=i/pi;
    long long ans=((a*inv(b,pk)%pk)*inv(c,pk)%pk)*ksm(pi,k,pk)%pk;
    ans=(ans*(p/pk)%p)*inv(p/pk,pk)%p;
    return ans;
}

long long exLucas(long long n,long m,long long p){
	long long x=p,pi,pk;
    long long ans=0;
    for(int i=2;i<=100000;i++)
        if(x%i==0){
            pk=1;pi=i;
            while(x%i==0) x/=i,pk*=i;
            ans=((ans+C(n,m,pi,pk))%p+p)%p;
        }
    return ans;
}

int main(){
	scanf("%lld %lld %d",&p,&n,&m);
	long long ans=1;
	long long x;
	for(int i=1;i<=m;i++){
		scanf("%lld",&x);
		if(x>n) {printf("Impossible");return 0;}
		(ans*=exLucas(n,x,p))%=p;
		n-=x;
	}
	printf("%lld\n",ans);
}

 

你可能感兴趣的:([国家集训队]礼物,洛谷P2183,扩展Lucas)