1. 程式人生 > >bzoj 1951: [Sdoi2010]古代豬文 【中國剩余定理+歐拉定理+組合數學+盧卡斯定理】

bzoj 1951: [Sdoi2010]古代豬文 【中國剩余定理+歐拉定理+組合數學+盧卡斯定理】

amp == pri pla 質因數分解 b+ return ons gcd

首先化簡,題目要求的是
\[ G^{\sum_{i|n}C_{n}^{i}}\%p \]
對於乘方形式快速冪就行了,因為p是質數,所以可以用歐拉定理
\[ G^{\sum_{i|n}C_{n}^{i}\%\varphi(p)} \]
\[ G^{\sum_{i|n}C_{n}^{i}\%p-1} \]
因為p-1不是質數,所以把它質因數分解為2,3,4679,35617,最後用中國剩余定理合並即可。

#include<iostream>
#include<cstdio>
using namespace std;
const int p=999911659,N=50005;
int
g,n,m[5],fac[5][N],t[5]={2,3,4679,35617}; int read() { int r=0,f=1; char p=getchar(); while(p>‘9‘||p<‘0‘) { if(p==‘-‘) f=-1; p=getchar(); } while(p>=‘0‘&&p<=‘9‘) { r=r*10+p-48; p=getchar(); } return r*f; } int
ksm(long long a,int b,int p) { long long r=1ll; while(b) { if(b&1) r=r*a%p; a=a*a%p; b>>=1; } return r; } int C(int n,int m,int x) { if(n<m) return 0; return fac[x][n]*ksm(fac[x][n-m]*fac[x][m],t[x]-2,t[x])%t[x]; } int
lucas(int n,int m,int x) { return !m?1:C(n%t[x],m%t[x],x)*lucas(n/t[x],m/t[x],x)%t[x]; } void exgcd(int a,int b,int &x,int &y) { if(b==0) { x=1,y=0; return; } exgcd(b,a%b,y,x); y-=a/b*x; } int wk() { int a,b,x,y; a=t[0],b=m[0]; for(int i=1;i<4;i++) { exgcd(a,t[i],x,y); x=(((m[i]-b)*x)%t[i]+t[i])%t[i]; b=b+a*x; a=a*t[i]; } return b; } int main() { for(int i=0;i<4;i++) { fac[i][0]=1; for(int j=1;j<=t[i];j++) fac[i][j]=fac[i][j-1]*j%t[i]; } n=read(),g=read(); if(g==p) { puts("0"); return 0; } g%=p; for(int i=1;i*i<=n;i++) if(n%i==0) { int now=n/i; for(int j=0;j<4;j++) { if(now!=i) m[j]=(m[j]+lucas(n,i,j))%t[j]; m[j]=(m[j]+lucas(n,now,j))%t[j]; } } printf("%d\n",ksm(g,wk(),p)); return 0; }

bzoj 1951: [Sdoi2010]古代豬文 【中國剩余定理+歐拉定理+組合數學+盧卡斯定理】