BZOJ1951 [Sdoi2010]古代猪文 NOIP数论大杂烩
https://www.lydsy.com/JudgeOnline/problem.php?id=1951
Description
猪王国的文明源远流长,博大精深。
iPig在大肥猪学校图书馆中查阅资料,得知远古时期猪文文字总个数为N。当然,一种语言如果字数很多,字典也相应会很大。当时的猪王国国王考虑到如果修一本字典,规模有可能远远超过康熙字典,花费的猪力、物力将难以估量。故考虑再三没有进行这一项劳猪伤财之举。当然,猪王国的文字后来随着历史变迁逐渐进行了简化,去掉了一些不常用的字。
iPig打算研究古时某个朝代的猪文文字。根据相关文献记载,那个朝代流传的猪文文字恰好为远古时期的k分之一,其中k是N的一个正约数(可以是1和N)。不过具体是哪k分之一,以及k是多少,由于历史过于久远,已经无从考证了。
iPig觉得只要符合文献,每一种能整除N的k都是有可能的。他打算考虑到所有可能的k。显然当k等于某个定值时,该朝的猪文文字个数为N / k。然而从N个文字中保留下N / k个的情况也是相当多的。iPig预计,如果所有可能的k的所有情况数加起来为P的话,那么他研究古代文字的代价将会是G的P次方。
现在他想知道猪王国研究古代文字的代价是多少。由于iPig觉得这个数字可能是天文数字,所以你只需要告诉他答案除以999911659的余数就可以了。
Input
输入有一行:两个数N、G,用一个空格分开。
Output
输出有一行:一个数,表示答案除以999911659的余数。
Sample Input
Sample Output
HINT
【数据规模】
10%的数据中,1 <= N <= 50;
20%的数据中,1 <= N <= 1000;
40%的数据中,1 <= N <= 100000;
100%的数据中,1 <= G <= 1000000000,1 <= N <= 1000000000。
此题用到了NOIP数论$\frac{2}{3}\qquad$的知识。
有费马小定理,Lucas定理,龟速幂,线性推逆元,扩展GCD,中国剩余定理,分解质因数的内容,一个一个来。
题目显然是让我们求G∑d|n Cdn mod P
因为P是一个质数,显然费马小定理成立ap-1 ≡ 1
之后G上面的数可以化成∑d|n Cdn(mod P-1)
999911658=2 × 3 × 4679 × 35617.
可以一层扩展Lucas,用中国剩余定理扩展之后合并,需要线性推逆元和扩展GCD。
之后分解质因数,龟速幂就好了!
#include<cstdio> #define mod 999911659 #define N 50000 typedef long long ll; ll in[5]={0,2,3,4679,35617}; ll M[N+2]; ll a[N+2]; ll n,G; ll fac[N+2][5]; ll inv[N+2][5]; ll m=mod-1; ll div[N+2]; ll idx; ll ans2; void init() { for(int j=1;j<=4;j++) { fac[0][j]=1; inv[in[j]-1][j]=in[j]-1; for(int i=1;i<=in[j];i++) fac[i][j]=(fac[i-1][j]*i)%in[j]; for(int i=in[j]-2;i>=0;i--) inv[i][j]=(inv[i+1][j]*(i+1))%in[j]; } } ll pow(ll x,ll y) { ll ans3=1; while(y) { if(y&1) ans3=(ans3*x)%mod; x=(x*x)%mod; y/=2; } return ans3; } ll lucas(ll n,ll m,ll i) { if(n<m) return 0; if(n<in[i]&&m<in[i]) return fac[n][i]*inv[m][i]%in[i]*inv[n-m][i]%in[i]; else return lucas(n/in[i],m/in[i],i)%in[i]*lucas(n%in[i],m%in[i],i)%in[i]; } void exgcd(ll a,ll b,ll &x,ll &y) { if(!b) { x=1; y=0; return; } exgcd(b,a%b,x,y); ll tmp=x; x=y; y=tmp-a/b*y; return; } ll China() { ll ans=0,x,y; for(int i=1;i<=4;i++) { M[i]=m/in[i]; exgcd(M[i],in[i],x,y); ans=(ans+a[i]*x*M[i])%m; } return (ans+m)%m; } int main() { scanf("%lld%lld",&n,&G); if(G==mod) { puts("0"); return 0; } init(); div[++idx]=1; for(int i=2;i*i<=n;i++) { if(n%i==0) { div[++idx]=i; if((i*i)!=n) div[++idx]=n/i; } } div[++idx]=n; for(int i=1;i<=idx;i++) { for(int j=1;j<=4;j++) a[j]=lucas(n,div[i],j); ans2=(ans2+China())%m; } ll ans=pow(G,ans2)%mod; printf("%lld",ans); }