[Sdoi2010]古代猪文
<body>
<center>
<h1>1951: [Sdoi2010]古代猪文</h1>
<span class="green">Time Limit: </span>1 Sec
<span class="green">Memory Limit: </span>64 MB<br>
<span class="green">Submit: </span>3897 <span class="green">Solved: </span>1772<br>[<a href="submitpage.php?id=1951">Submit</a>][<a href="problemstatus.php?id=1951">Status</a>][<a href="bbs.php?id=1951">Discuss</a>]
</center><h2>Description</h2><div class="content">
<p>
“在那山的那边海的那边有一群小肥猪。他们活泼又聪明,他们调皮又灵敏。他们自由自在生活在那绿色的大草坪,他们善良勇敢相互都关心……”<br>
——选自猪王国民歌
</p>
<p>
很久很久以前,在山的那边海的那边的某片风水宝地曾经存在过一个猪王国。猪王国地理位置偏僻,实施的是适应当时社会的自给自足的庄园经济,很少与外界联系,商贸活动就更少了。因此也很少有其他动物知道这样一个王国。<br>
猪王国虽然不大,但是土地肥沃,屋舍俨然。如果一定要拿什么与之相比的话,那就只能是东晋陶渊明笔下的大家想象中的桃花源了。猪王勤政爱民,猪民安居乐业,邻里和睦相处,国家秩序井然,经济欣欣向荣,社会和谐稳定。和谐的社会带给猪民们对工作火红的热情和对未来的粉色的憧憬。<br>
小猪iPig是猪王国的一个很普通的公民。小猪今年10岁了,在大肥猪学校上小学三年级。和大多数猪一样,他不是很聪明,因此经常遇到很多或者稀奇古怪或者旁人看来轻而易举的事情令他大伤脑筋。小猪后来参加了全猪信息学奥林匹克竞赛(Pig Olympiad in Informatics, POI),取得了不错的名次,最终保送进入了猪王国大学(Pig Kingdom University, PKU)深造。<br>
现在的小猪已经能用计算机解决简单的问题了,比如能用P++语言编写程序计算出A + B的值。这个“成就”已经成为了他津津乐道的话题。当然,不明真相的同学们也开始对他刮目相看啦~
小猪的故事就将从此展开,伴随大家两天时间,希望大家能够喜欢小猪。<br>
</p>
<div>题目描述</div>
<p>
猪王国的文明源远流长,博大精深。<br>
iPig在大肥猪学校图书馆中查阅资料,得知远古时期猪文文字总个数为N。当然,一种语言如果字数很多,字典也相应会很大。当时的猪王国国王考虑到如果修一本字典,规模有可能远远超过康熙字典,花费的猪力、物力将难以估量。故考虑再三没有进行这一项劳猪伤财之举。当然,猪王国的文字后来随着历史变迁逐渐进行了简化,去掉了一些不常用的字。<br>
iPig打算研究古时某个朝代的猪文文字。根据相关文献记载,那个朝代流传的猪文文字恰好为远古时期的k分之一,其中k是N的一个正约数(可以是1和N)。不过具体是哪k分之一,以及k是多少,由于历史过于久远,已经无从考证了。<br>
iPig觉得只要符合文献,每一种能整除N的k都是有可能的。他打算考虑到所有可能的k。显然当k等于某个定值时,该朝的猪文文字个数为N / k。然而从N个文字中保留下N / k个的情况也是相当多的。iPig预计,如果所有可能的k的所有情况数加起来为P的话,那么他研究古代文字的代价将会是G的P次方。<br>
现在他想知道猪王国研究古代文字的代价是多少。由于iPig觉得这个数字可能是天文数字,所以你只需要告诉他答案除以999911659的余数就可以了。<br>
</p>
</div><h2>Input</h2><div class="content">有且仅有一行:两个数N、G,用一个空格分开。
</div><h2>Output</h2><div class="content">有且仅有一行:一个数,表示答案除以999911659的余数。
</div><h2>Sample Input</h2>
<div class="content"><span class="sampledata">4 2<br>
</span></div><h2>Sample Output</h2>
<div class="content"><span class="sampledata">2048<br>
</span></div><h2>HINT</h2>
<div class="content"><p>10%的数据中,1 <= N <= 50;<br>
20%的数据中,1 <= N <= 1000;<br>
40%的数据中,1 <= N <= 100000;<br>
100%的数据中,1 <= G <= 1000000000,1 <= N <= 1000000000。<br>
</p></div><h2>Source</h2>
<div class="content"><p><a href="problemset.php?search=Sdoi2010 Contest2">Sdoi2010 Contest2</a></p></div><center>[<a href="submitpage.php?id=1951">Submit</a>][<a href="problemstatus.php?id=1951">Status</a>][<a href="bbs.php?id=1951">Discuss</a>]</center><br>
<a href="./"><span class="red">HOME</span></a>
<a href="javascript:history.go(-1)"><span class="red">Back</span></a>
</body>
hzwer的题解
求G^M mod P,M=∑ i|N C(N,i),P=999911659。
G^M mod P = G^(M mod (P-1) ) ( G != P)。
所以只要得出 M mod (P-1) 即可用快速幂求出答案。
N的约数可以在√n的时间内求出,所以问题转化为求C(N,i) mod (P-1)。
发现p-1不是一个质数,P-1=234679*35617,所以只能求出C(N,i) mod 每个因数的值。
得到4个取模方程,最后用合并模线性方程组。
#include<bits/stdc++.h>
#define rg register
#define il inline
#define co const
template<class T>il T read(){
rg T data=0,w=1;
rg char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') w=-1;
ch=getchar();
}
while(isdigit(ch))
data=data*10+ch-'0',ch=getchar();
return data*w;
}
template<class T>il T read(rg T&x){
return x=read<T>();
}
typedef long long ll;
co int P=999911659;
int G,N,M[4];
int fac[4][40005];
int t[4]={2,3,4679,35617};
int qpow(ll a,int b,int p){
int ans=1;
for(int i=b;i;i>>=1,a=(a*a)%p)
if(i&1) ans=(ans*a)%p;
return ans;
}
int C(int n,int m,int x){
if(n<m) return 0;
return fac[x][n]*qpow(fac[x][n-m]*fac[x][m],t[x]-2,t[x])%t[x];
}
int lucas(int n,int m,int x){
if(m==0) return 1;
return 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,x,y);
int t=x;x=y,y=t-a/b*y;
}
int solve(){
int a1,b1,a2,b2,a,b,c,x,y;
a1=t[0],b1=M[0];
for(int i=1;i<4;++i){
a2=t[i],b2=M[i];
a=a1,b=a2,c=b2-b1;
exgcd(a,b,x,y);
x=((c*x)%b+b)%b;
b1=b1+a1*x;
a1=a1*b;
}
return b1;
}
int main()
{
// freopen(".in","r",stdin),freopen(".out","w",stdout);
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];
}
read(N),read(G);
if(G==P){puts("0");return 0;}
G%=P;
for(int i=1;i*i<=N;++i) if(N%i==0){
int tmp=N/i;
for(int j=0;j<4;++j){
if(tmp!=i) M[j]=(M[j]+lucas(N,i,j))%t[j];
M[j]=(M[j]+lucas(N,tmp,j))%t[j];
}
}
printf("%d\n",qpow(G,solve(),P));
return 0;
}
静渊以有谋,疏通而知事。
浙公网安备 33010602011771号