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;
}


posted @ 2015-10-05 19:48  buzhidaohahaha  阅读(169)  评论(0编辑  收藏  举报