bzoj2142
参考链接:
http://blog.csdn.net/popoqqq/article/details/39891263
http://blog.csdn.net/yerongsc/article/details/8768957
需要转化一下:
ans=C(n,w1)*C(n-w1,w2)*C(n-w1-w2,w3)*...*C(n-w1-w2-...-w_(m-1),wm) mod P
=n!/w1!/w2!/.../wm! mod P
假设P=p1^a1*p2^a2+……+pn^an
这个题转化成中国剩余定理时应该模上p1^a1,p2^a2……,pn^an (1),而不是模上p1,p2,……pn(2)
假设按照第2种方法算出来符合条件的x,x加上或减去p1*p2*……*pn,仍符合条件,但是这样就有可能在0到P-1之间存在一个以上符合条件的,那么就不能确定是哪一个,因为一个确定的数模上P也是一个确定的数,在0到P-1之间只有一个值。
(跟这帮二百五一起执行任务,就像骑士骑着叫驴冲向战场,即便你高举马刀吼声如雷已经有为国捐躯之志,你也没法确定自己能杀入敌阵。因为你胯下的驴随时会撒起欢来甩开四蹄带你奔向天边。 ——江南 《龙族》)
已ac的代码:
#include<stdio.h> #include<string.h> #include<iostream> using namespace std; #define M 10 #define N 100010 int pergift[M]; int pi[N]; int perpi[N]; int picou; int b[N]; long long int km(long long int x,int y,int mod){ long long int ans=1; while(y){ if(y%2){ ans=ans*x%mod; } x=x*x%mod; y=y/2; } return ans; } pair<int,int> ffa(int x,int mod,int permod){ //printf("wo shi da hao ren"); //printf("%d %d %dha\n",x,mod,permod); if(x==0){ return make_pair(0,1); } else{ long long int ans=1; pair<int,int> temp; for(int i=1;i<=mod-1;i++){//少写了个=号 if(i%permod!=0){ ans=ans*i%mod; } } ans=km(ans,x/mod,mod);//km返回long long int型 for(int i=1;i<=x%mod;i++){ if(i%permod!=0){ ans=ans*i%mod; } } temp=ffa(x/permod,mod,permod); ans=ans*temp.second%mod; temp.second=ans; temp.first+=x/permod; //printf("%d %d %d %d %dha\n",x,mod,permod,temp.first,temp.second); return temp; } } void exgcd(long long int *a,long long int *b,int x,int y){ if(y==0){ *a=1; *b=1; return; } else{ long long int a1,b1; exgcd(&a1,&b1,y,x%y); *a=b1; *b=a1-x/y*b1; return; } } int inv(int x,int y){ long long int a,b; exgcd(&a,&b,x,y); a=(a%y+y)%y; return (int)a; } int calculate(int n,int m,int mod,int permod){ pair<int,int> pn,pm,tempp; pn=ffa(n,mod,permod); //printf("%d %d %d %d %d\n",n,mod,permod,pn.first,pn.second); pm.first=0; pm.second=1; for(int i=0;i<m;i++){ tempp=ffa(pergift[i],mod,permod); pm.first+=tempp.first; pm.second=(long long int)pm.second*tempp.second%mod; } return km(permod,pn.first-pm.first,mod)*pn.second%mod*inv(pm.second,mod)%mod;//pn和pm写反了,这里这个式子计算完后,本来是long long int型的,但是因为返回int型的,看来自动转化成了int,不强制转化也是可以的。 } long long int bigpro(long long int a,long long int b,long long int mod){ long long int ans=0; while(b){ if(b%2){ ans=(ans+a)%mod; } a=(a+a)%mod; b=b/2; } return ans; } long long int fwaycou(int n,int m,long long int p){ long long int tempp=p; long long int ans=0; picou=0; for(int i=2;i*i<=tempp;i++){ if(tempp%i==0){ pi[picou]=1; while(tempp%i==0){ pi[picou]*=i; tempp/=i; } perpi[picou++]=i; } } if(tempp!=1){//恭喜,又一次成功的忘记了这个判断! pi[picou]=tempp; perpi[picou++]=tempp; } for(int i=0;i<picou;i++){ b[i]=calculate(n,m,pi[i],perpi[i]); //printf("%d\n",b[i]); } ans=0; for(int i=0;i<picou;i++){ //printf("%lld %lld %d ha1\n",bigpro(p/pi[i],b[i],p),bigpro(bigpro(p/pi[i],b[i],p),inv(p/pi[i],pi[i]),p),inv(p/pi[i],pi[i])); ans=(ans+bigpro(bigpro(p/pi[i],b[i],p),inv(p/pi[i],pi[i]),p))%p;//ans加上一个数后,忘了%p,所以wr了。 } return ans; } int main(){ long long int p; int n,m; while(scanf("%lld",&p)!=EOF){ scanf("%d%d",&n,&m); int sum=0; for(int i=0;i<m;i++){ scanf("%d",&pergift[i]); sum+=pergift[i]; } if(sum>n){ printf("Impossible\n"); } else{ pergift[m++]=n-sum; printf("%lld\n",fwaycou(n,m,p)); } } return 0; }
又一遍ac代码:
#include<stdio.h> #include<string.h> #include<iostream> using namespace std; #define N 10 #define M 100010 int pergift[M]; int pi[N]; int picou; int perpi[N]; int b[N]; long long int km(long long int x,long long int y,long long int mod){//注意x要是long long int型的,因为在x*x时int可能超范围。 long long int ans=1; while(y){ if(y%2){ ans=ans*x%mod; } y=y/2; x=x*x%mod; } return ans; } pair<int,int> ffa(int n,int mod,int permod){ pair<int,int> ans; //printf("%d %d %d\n",n,mod,permod); if(n==0){ ans.first=0; ans.second=1; } else{ long long int temp=1; for(int i=1;i<mod;i++){ if(i%permod!=0){ temp=temp*i%mod; } } temp=km(temp,n/mod,mod); for(int i=1;i<=n%mod;i++){ if(i%permod!=0){ temp=temp*i%mod; } } ans=ffa(n/permod,mod,permod); ans.first+=n/permod; ans.second=(int)(temp*ans.second%mod); } //printf("wo shi da hao ren"); return ans; } long long int bigpro(long long int x,long long int y,long long int mod){ long long int ans=0; while(y){ if(y%2){ ans=(ans+x)%mod; } y=y/2; x=(x+x)%mod; } return ans; } void exgcd(long long int *a,long long int *b,int x,int y){ if(y==0){ *a=1; *b=1; } else{ long long int a1,b1; exgcd(&a1,&b1,y,x%y); *a=b1; *b=a1-x/y*b1; } return; } int inv(int x,int y){ long long int a,b; exgcd(&a,&b,x,y); return (int)((a%y+y)%y); } int qmod(int n,int m,int mod,int permod){ pair<int,int> pn,pm,temp; pn=ffa(n,mod,permod); pm.first=0; pm.second=1; for(int i=0;i<m;i++){ temp=ffa(pergift[i],mod,permod); pm.first+=temp.first; pm.second=(int)((long long int)pm.second*temp.second%mod); } return (int)(km(permod,pn.first-pm.first,mod)*pn.second%mod*inv(pm.second,mod)%mod);//km要返回long long int型的 } long long int fop(int n,int m,long long int p){ long long int tempp=p; long long int ans=0; picou=0; for(int i=2;i*i<=tempp;i++){//当p是1时可以吗? if(tempp%i==0){ pi[picou]=1; while(tempp%i==0){ pi[picou]*=i; tempp/=i; } perpi[picou++]=i; } } if(tempp!=1){ pi[picou]=tempp; perpi[picou++]=tempp; } for(int i=0;i<picou;i++){ b[i]=qmod(n,m,pi[i],perpi[i]); } for(int i=0;i<picou;i++){//这里是要应用中国剩余定理,合并同余方程,所以应该是遍历所有可能的余数,而不是m,m和这里完全没有任何关系。 //printf("%d\n",b[i]); ans=(ans+bigpro(bigpro(p/pi[i],b[i],p),inv(p/pi[i],pi[i]),p))%p;//printf("wo shi da hao ren\n"); } return ans; } int main(){ long long int p; int n,m; int sum; while(scanf("%lld\n",&p)!=EOF){ scanf("%d%d",&n,&m); sum=0; for(int i=0;i<m;i++){ scanf("%d",&pergift[i]); sum+=pergift[i]; } if(n<sum){ printf("Impossible\n"); } else{ pergift[m++]=n-sum; printf("%lld\n",fop(n,m,p));//printf("wo shi da hao ren"); } } return 0; }