参考链接:
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;
}