FZOJ#181. 【2017FZSZ寒假集训-DAY10】告

【问题描述】

定义 S 为, 对于所有可以整除 n 的整数 k(包括 1 和n ) , C(n,k)之和. 求 GS 除以 999911659 的余数.

【输入格式】

共一行, 两个整数 n , G .

【输出格式】

一个整数, 如题所述.

【样例输入】4  2

【样例输入】2048

【样例解释】

k=1,2,4

S=C(4,1)+C(4,2)+C(4,4)=11

Gs=211=2048

【数据规模】

对于 10 的数据, 1n50

对于 20 的数据, 1n103 。

对于 40 的数据, 1n105 。

对于 100 的数据, 1G109 , 1n109 。

【时间限制】1s

【空间限制】256M

【题解】

        看到这题首先想到的就是lucas,然而发现是GS不能直接模99991165。 根据费马小定理,我们可以把S对于999911658取模。然而还是太大了。我们发现这时候我们需要的模数已经不是一个质数了,所以我们可以运用中国剩余定理。接下来给出中国剩余定理的证明。

 

        

     对于如上图这样的一个式子,我们就会用到中国剩余定理。

     我们设一个数Yi。对于每一个Yi都满足Yi ≡ 1(mod  mi)且  Yi  ≡  0(mod mj)(j ≠ i)。

     现在我们设M= ​ ,N,K为任意常数。

     根据 Yi  的定义,我们可以知道下面这两个式子

      Yi  = mi × N + 1

      Yi  =  M / mi × K

      联立两个式子可得  mi × N + 1  =   M / mi × K

      整理得   -mi× N+M / mi × K  =  1

      又因为mi都是质数,所以gcd( -mi,M / mi )=1

      所以 -mi× N+M / mi × K  =  gcd( -mi,M / mi )

      然后我们就可以用exgcd来求解啦。

      S = ​  (M/mi) ×ai ×K i

 

 

 【代码】

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
#define LL long long
LL n,G;
LL mod=999911659,fac[5][40001];
LL mm[5]={999911659,2,3,4679,35617},a[5]={};
void init(){
    fac[1][0]=fac[2][0]=fac[3][0]=fac[4][0]=1;
    for(int j=1;j<=4;j++){
        for(int i=1;i<=40000;i++)
          fac[j][i]=fac[j][i-1]*(LL)i%mm[j];
    }
  }
LL power(LL x,LL y,LL now){
    LL r=1;
    x%=mm[now];
    while(y){
        if(y&1) r=(r*x)%mm[now];
        x=(x*x)%mm[now];y>>=1;
    }
    return r;
}
LL C(LL n,LL m,LL now){
    if(n==m) return 1LL;
    if(m>n) return 0;
    return (fac[now][n]*power((fac[now][n-m]*fac[now][m])%mm[now],mm[now]-2,now))%mm[now];
}
LL lucas(LL n,LL m,LL now){
    if(!m) return 1;
    return (C(n%mm[now],m%mm[now],now)*lucas(n/mm[now],m/mm[now],now))%mm[now];
}
void gcd(LL a,LL b,LL &x,LL &y){
    if(!b){
        x=1;y=0;return;
    }
    gcd(b,a%b,x,y);
    LL tmp=x;x=y;y=tmp-a/b*y;
}
LL crt(LL a,LL b,LL c,LL d){
    LL r[5]={0,a,b,c,d};
    LL p=mod-1,ans=0;
    for(int i=1;i<=4;i++){
        LL mi=p/mm[i],v=0,y=0;
        gcd(mi,mm[i],v,y);
        ans=(ans+v*mi*r[i])%p;
    }
    return (ans+p)%p;
}
void work(LL x){
    LL modn;
    for(int i=1;i<=4;i++){
        modn=mm[i];
        a[i]+=lucas(n,x,i);
        a[i]%=modn;
    }
}
int main(){
    init();
    scanf("%lld%lld",&n,&G);
    if(G==mod){
        puts("0");return 0;
    }
    G%=mod;
    for(int i=1;i*i<=n;i++){
        if(n%i==0){
            work(i);
            if(i*i!=n) work(n/i);
        }
    }
    LL sum=crt(a[1],a[2],a[3],a[4]);
    printf("%lld",power(G,sum,0LL));
    return 0;
}  
View Code

 

 

posted on 2017-03-21 19:38  Sydney_Sun  阅读(196)  评论(0)    收藏  举报