• BZOJ.2142.礼物(扩展Lucas)


    题目链接

    答案就是C(n,m1) * C(n-m1,m2) * C(n-m1-m2,m3)...(mod p)
    使用扩展Lucas求解。
    一个很简单的优化就是把pi,pi^ki次方存下来,因为每次分解p都是很慢的。
    注意最后p不为1要把p再存下来!(质数)

    COGS 洛谷上的大神写得快到飞起啊QAQ 就这样吧

    3.25 Update:预处理阶乘可以很快,别忘longlong。代码见下。

    //836kb	288ms
    #include <cmath>
    #include <cstdio>
    typedef long long LL;
    
    int cnt,P[500],PK[500];
    LL FP(LL x,int k,LL p)
    {
    	LL t=1ll;
    	for(; k; k>>=1,x=x*x%p)
    		if(k&1) t=t*x%p;
    	return t;
    }
    LL Exgcd(LL a,LL b,LL &x,LL &y)
    {
    	if(!b) x=1,y=0;
    	else Exgcd(b,a%b,y,x),y-=a/b*x;
    }
    LL Inv(LL a,LL p)
    {
    	LL x,y; Exgcd(a,p,x,y);
    	return (x%p+p)%p;
    }
    LL Fact(LL x,LL pi,LL pk)//Calc x! % (pk=pi^ki)(x!中无pi因子)
    {
    	if(!x) return 1ll;
    	LL res=1ll;
    	if(x>=pk)
    	{
    		for(int i=2; i<pk; ++i)//从1开始没什么用 
    			if(i%pi) (res*=i)%=pk;//无pi因子!
    		res=FP(res,x/pk,pk);
    	}
    	for(int i=2; i<=x%pk; ++i)
    		if(i%pi) (res*=i)%=pk;
    	return res*Fact(x/pi,pi,pk)%pk;
    }
    int C(LL n,LL m,LL pi,LL pk,LL mod)//int
    {
    	if(n<m) return 0;
    	LL a=Fact(n,pi,pk),b=Fact(m,pi,pk),c=Fact(n-m,pi,pk);int k=0;
    	for(LL i=n; i; i/=pi) k+=i/pi;
    	for(LL i=m; i; i/=pi) k-=i/pi;
    	for(LL i=n-m; i; i/=pi) k-=i/pi;
    	LL res=a*Inv(b,pk)%pk*Inv(c,pk)%pk*FP(pi,k,pk)%pk;
    	return res*(mod/pk)%mod*Inv(mod/pk,pk)%mod;
    }
    LL Solve(int n,int m,int p)
    {
    	if(!n) return 1ll;
    	int res=0;
    	for(int i=1; i<=cnt; ++i) (res+=C(n,m,P[i],PK[i],p))%=p;
    	return (LL)res;
    }
    
    int main()
    {
    	int n,m,p,t[9];
    	scanf("%d%d%d",&p,&n,&m);
    	int sum=0;
    	for(int i=1; i<=m; ++i) scanf("%d",&t[i]),sum+=t[i];
    	if(sum>n) {puts("Impossible"); return 0;}
    	int now=p;
    	for(int i=2,lim=sqrt(p+0.5); i<=lim; ++i)
    		if(!(now%i))
    		{
    			int pk=1;
    			while(!(now%i)) now/=i,pk*=i;
    			P[++cnt]=i, PK[cnt]=pk;
    			if(now==1) break;
    		}
    	if(now!=1) P[++cnt]=now,PK[cnt]=now;
    	LL res=1ll;
    	for(int i=1; i<=m; ++i) (res*=Solve(n,t[i],p))%=p,n-=t[i];
    	printf("%lld",res);
    
    	return 0;
    }
    

    Update:

    /*
    1620kb	184ms
    不预处理:836kb	288ms
    答案就是C(n,m1)*C(n-m1,m2)*C(n-m1-m2,m3)...使用扩展Lucas求解。
    一个很简单的优化就是把pi,pi^ki次方存下来,因为每次分解p都是很慢的。
    注意最后p不为1要把p再存下来!(质数)
    预处理阶乘。不想麻烦就开longlong。
    */
    #include <cmath>
    #include <cstdio>
    typedef long long LL;
    
    int cnt,P[500],PK[500];
    LL fac[100005];//开longlong!
    LL FP(LL x,int k,LL p)
    {
    	LL t=1ll;
    	for(; k; k>>=1,x=x*x%p)
    		if(k&1) t=t*x%p;
    	return t;
    }
    LL Exgcd(LL a,LL b,LL &x,LL &y)
    {
    	if(!b) x=1,y=0;
    	else Exgcd(b,a%b,y,x),y-=a/b*x;
    }
    LL Inv(LL a,LL p)
    {
    	LL x,y; Exgcd(a,p,x,y);
    	return (x%p+p)%p;
    }
    LL Fact(LL x,LL pi,LL pk)//Calc x! % (pk=pi^ki)(x!中无pi因子)
    {
    	if(!x) return 1ll;
    	LL res=1ll;
    	if(x>=pk) res=FP(fac[pk],x/pk,pk);
    	res=res*fac[x%pk]%pk;
    	return res*Fact(x/pi,pi,pk)%pk;
    }
    int C(LL n,LL m,LL pi,LL pk,LL mod)//int
    {
    	if(n<m) return 0;
    	fac[0]=1;
    	for(int i=1; i<=pk; ++i)
    		if(i%pi) fac[i]=1ll*fac[i-1]*i%pk;
    		else fac[i]=fac[i-1];
    	LL a=Fact(n,pi,pk),b=Fact(m,pi,pk),c=Fact(n-m,pi,pk);int k=0;
    	for(LL i=n; i; i/=pi) k+=i/pi;
    	for(LL i=m; i; i/=pi) k-=i/pi;
    	for(LL i=n-m; i; i/=pi) k-=i/pi;
    	LL res=a*Inv(b,pk)%pk*Inv(c,pk)%pk*FP(pi,k,pk)%pk;
    	return res*(mod/pk)%mod*Inv(mod/pk,pk)%mod;
    }
    LL Solve(int n,int m,int p)
    {
    	if(!n) return 1ll;
    	int res=0;
    	for(int i=1; i<=cnt; ++i) (res+=C(n,m,P[i],PK[i],p))%=p;
    	return (LL)res;
    }
    
    int main()
    {
    	int n,m,p,t[9];
    	scanf("%d%d%d",&p,&n,&m);
    	int sum=0;
    	for(int i=1; i<=m; ++i) scanf("%d",&t[i]),sum+=t[i];
    	if(sum>n) {puts("Impossible"); return 0;}
    	int now=p;
    	for(int i=2,lim=sqrt(p+0.5); i<=lim; ++i)
    		if(!(now%i))
    		{
    			int pk=1;
    			while(!(now%i)) now/=i,pk*=i;
    			P[++cnt]=i, PK[cnt]=pk;
    			if(now==1) break;
    		}
    	if(now!=1) P[++cnt]=now,PK[cnt]=now;
    	LL res=1ll;
    	for(int i=1; i<=m; ++i) (res*=Solve(n,t[i],p))%=p,n-=t[i];
    	printf("%lld",res);
    
    	return 0;
    }
    
  • 相关阅读:
    关于GridView Master-Detail 不支持明细属性为IEnumerable、IList问题
    GridControl摘录
    DevExpress中chartControl中实现统计图功能
    DevExpress中GridControl列转义的实现方法
    DevExpress实现根据行,列索引来获取RepositoryItem的方法
    修改yum源为阿里云的
    使用sendmail来发邮件
    nginx默认访问目录时显示403错误
    同时调整lv分区的大小(减少一个,增加另一个)
    ORA-00257错误的解决办法
  • 原文地址:https://www.cnblogs.com/SovietPower/p/8627539.html
Copyright © 2020-2023  润新知