bzoj 1951
这道题告诉了我们一个很重要的道理:看到题,先想明白再动手!
题意:求对999911659取模的值
首先,由于n的数据范围不是很大(至少不是很大),所以可以O()枚举所有约数分别求组合数
但是有个问题:根据费马小定理,
所以组合数应当对p-1取模!
可是p-1并不是一个质数啊
所以我们要将p-1质因子分解,发现可以分解成四个质数之积,那么我们用四次卢卡斯定理分别计算出四个结果再用中国剩余定理合并即可。
但我真正想说的是,如果做过礼物的话,很容易误以为这题要用拓展卢卡斯定理,然后写到死...
所以千万不要像我一样...
#include <cstdio> #include <cmath> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #include <queue> #include <stack> #define mode 999911659 #define mo 999911658 #define ll long long using namespace std; ll inv[40000][5]; ll mul[40000][5]; ll mod[5]={0,2,3,4679,35617}; ll a[5]; ll n,g; ll pow_mul(ll x,ll y) { ll ans=1; while(y) { if(y%2) { ans*=x; ans%=mode; } x*=x; x%=mode; y/=2; } return ans; } void init() { for(int i=1;i<=4;i++) { inv[0][i]=inv[1][i]=mul[0][i]=mul[1][i]=1; for(int j=2;j<mod[i];j++) { inv[j][i]=(mod[i]-mod[i]/j)*inv[mod[i]%j][i]%mod[i]; } for(int j=2;j<mod[i];j++) { inv[j][i]=inv[j-1][i]*inv[j][i]%mod[i]; mul[j][i]=mul[j-1][i]*j%mod[i]; } } } ll C(ll x,ll y,ll num) { if(x<y) { return 0; }else if(x==y) { return 1; }else if(x<mod[num]) { return mul[x][num]*inv[y][num]%mod[num]*inv[x-y][num]%mod[num]; }else { return C(x/mod[num],y/mod[num],num)*C(x%mod[num],y%mod[num],num)%mod[num]; } } void ex_gcd(ll a,ll b,ll &x,ll &y) { if(b==0) { x=1; y=0; return; } ex_gcd(b,a%b,x,y); ll t=x; x=y; y=t-(a/b)*x; } ll china() { ll M=mo; ll ans=0; for(int i=1;i<=4;i++) { ll M0=M/mod[i]; ll x,y; ex_gcd(M0,mod[i],x,y); x=(x%mod[i]+mod[i])%mod[i]; ans+=x*M0%mo*a[i]%mo; } return ans; } ll solve(ll x,ll y) { for(int i=1;i<=4;i++) { a[i]=C(x,y,i); } return china(); } int main() { scanf("%lld%lld",&n,&g); init(); ll s=0; for(int i=1;i*i<=n;i++) { if(n%i==0) { s+=solve(n,i); s%=mo; if(n/i!=i) { s+=solve(n,n/i); } } } printf("%lld\n",pow_mul(g,s)); return 0; }