tag:Lucas定理,快速幂,扩展欧几里得,中国剩余定理
第一次做这么恶心的数论题,真心写的想吐了。
题目还是粘一下吧,还是蛮好的一个题呀:
1951: [Sdoi2010]古代猪文
Time Limit: 1 Sec Memory Limit: 64 MBSubmit: 681 Solved: 236
[ Submit][ Status]
Description
Input
Output
Sample Input
Sample Output
HINT
10%的数据中,1 <= N <= 50;
20%的数据中,1 <= N <= 1000;
40%的数据中,1 <= N <= 100000;
100%的数据中,1 <= G <= 1000000000,1 <= N <= 1000000000。
Source
题意:题目给出 n,g,要求所有满足 x 整除 n 的情况下,C(n,x)的和对 999911659 取余的结果作为幂,然后求g的这么多次幂取余的结果。
思路:由于p=999911659 是个大素数,根据上篇写的指数循环节的相关知识可以得到 (g^y )%p = (g^(y%phi(p)+phi(p)))%p 同时phi(p)=p-1 带进去得到 (g^y)%p = (g^(y%(p-1)))% p
关于由n和约数得到的组合数,用Lucas定理可以解决,跟前几篇写的一样,不过打阶乘表,只需要打到 35617 ,剩下的就不废话了。
讨论一下p , 由于当前的 mod = p-1 = 999911658 = 2 * 3 * 4679 * 35617 , 如果当前需要进行取余的数已经求出来了,那么我们直接对mod取余就很容易是溢出的结果来进行取余,所以要把这个取余分成四个同余方程,然后用中国剩余定理合并,就搞定了
#include <cstring>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstdio>
using namespace std;
#define maxn 35620
typedef long long LL;
LL w[4]={2,3,4679,35617};
LL a[4]={0,0,0,0};
LL fac[4][maxn];
LL Pow(LL a,LL b,LL mod)
{
LL ans=1;
while(b)
{
if(b&1)
{
b--;
ans=(ans*a)%mod;
}
else
{
b/=2;
a=(a*a)%mod;
}
}
return ans;
}
void init()
{
for(int i=0;i<4;i++)
{
fac[i][0]=1;
for(int j=1;j<=w[i];j++)
{
fac[i][j]=(fac[i][j-1]*j)%w[i];
}
}
}
LL C(LL n,LL m,int x)
{
if(n<m)
return 0;
return (fac[x][n]*Pow((fac[x][n-m]*fac[x][m]),w[x]-2,w[x]))%w[x];
}
LL Lucas(LL n,LL m,int x)
{
if(m==0)
return 1;
return (Lucas(n/w[x],m/w[x],x)*C(n%w[x],m%w[x],x))%w[x];
}
LL exgcd(LL a,LL b,LL &x,LL &y)
{
if(b==0)
{
x=1;
y=0;
return a;
}
else
{
LL ans=exgcd(b,a%b,x,y);
LL t=x;
x=y;
y=t-a/b*y;
return ans;
}
}
LL CRT(int r)
{
LL M=1;
LL i,d,x0,y0,ans=0;
for(i=0;i<r;i++)
M*=w[i];//好像很容易溢出的样子,CRT弱爆了
for(i=0;i<r;i++)
{
d=M/w[i];
exgcd(d,w[i],x0,y0);
ans=(ans+d*x0*a[i])%M;
}
while(ans<= 0)
ans+=M;
return ans;
}
int main()
{
init();
LL g,n;
while(cin>>n>>g)
{
g%=999911659;
memset(a,0,sizeof(a));
for(int i=1;i*i<=n;i++)
{
if(n%i==0)
{
LL tmp=n/i;
for(int j=0;j<4;j++)
{
if(tmp!=i)
a[j]=(a[j]+Lucas(n,i,j))%w[j];
a[j]=(a[j]+Lucas(n,tmp,j))%w[j];
}
}
}
cout<<Pow(g,CRT(4),999911659)<<endl;
}
return 0;
}