Problem G: JSOI2012 爱之项链
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 13 Solved: 5
[Submit][Status][Discuss]
Description
在进香河,流传着这样一段美丽的故事。zyg与kzn是两个生活在进香河的孩子,一天,他们两人闹矛盾了,于是zyg送给了kzn一条精美的爱之项链。从此他们幸福生活在一起。
这则故事的真实性到今天已经没有意义了,然而我们关注的是那一条精美的爱之项链。这是一条由N个精致的戒指与一块特殊纪念品相连而成的环形,如下图中的爱心符号正是一种特殊纪念品。(据说是2012年情人节时zyg特意托人订制的)上面的每一枚戒指又是由M个带磁性的特殊彩色球状物组成的环形。也许你会认为,这所谓的戒指,更像是一条条小项链。
下图给出了一种可行的方案,其中左边描述的是单一的一枚戒指,右图描述的是项链。
这里,所有带磁性的特殊彩色球状物的颜色只有R种,这里我们用1到R来表示。如果一枚戒指可以通过顺时针或逆时针的旋转后与另外一枚戒指相同,则认为这是两枚相同的戒指。
对于一条爱之项链,要求满足任何相邻两枚戒指必须是不相同的。同时,特殊纪念品左右两枚戒指也必须是不同的。
现在给定N,M和R,问究竟有多少种不同的爱之项链。
注意:
1、特殊纪念品的插入位置不同,也许会得到不同的爱之项链。
2、这里我们只考虑旋转后是否相同,不考虑翻转操作,这一点不论是对于每一枚戒指,还是对于整条项链,都是这样的。
Input
一行,三个正整数,分别是N,M和R。
Output
一行,表示有多少种不同的爱之项链。你只需要将答案模3214567。
Sample Input
10 5 4
Sample Output
1398595
HINT
对于100%的数据,N<=10^15,M<=10^9,R<=10^6。
题解:先用polya求出戒指种类m,于是问题转化为给你一个大小为n的环和m种颜色,求染色方案使得相邻颜色两两不同!
•设一个F[n]表示为大小为n的环的方案数
•求F[n]有两种方式
•设g[i][0]表示长度为i的开头和末尾相同的序列的个数,g[i][1]表示表示长度为i的开头和末尾不相同的序列的个数。
那么最后的答案f(n)=g[n][1]。f表示的是一个和的形式,但是在求g[n][1]的过程中就已经统计过了长度是n的约数的序列的个数了。
比如在统计长度为6的时候,就会把123123这种序列统计进去了。素以这样求是正确的。
g[i][0]=g[i−1][1]
g[i][1]=(o−2)g[i][1]+(o−1)g[i−1][0]
=(o−2)g[i][1]+(o−1)g[i−2][1]
所以f(n)=(o−2)f(n−1)+(o−1)f(n−2)
这个东西可以矩乘,也可以用特征根求通项。
r2=(o−2)r+(o−1)
解出来r1=−1,r2=d−1
然后f(n)=c1∗r1n+c2∗r2n
可以把f(1)=0,f(2)=d∗(d−1)带入就可以求出c1,c2
解得c1=d−1,c2=1
f(n)=(d−1)(−1)n+(d−1)n
那么最后的答案f(n)=g[n][1]。f表示的是一个和的形式,但是在求g[n][1]的过程中就已经统计过了长度是n的约数的序列的个数了。
比如在统计长度为6的时候,就会把123123这种序列统计进去了。素以这样求是正确的。
g[i][0]=g[i−1][1]
g[i][1]=(o−2)g[i][1]+(o−1)g[i−1][0]
=(o−2)g[i][1]+(o−1)g[i−2][1]
所以f(n)=(o−2)f(n−1)+(o−1)f(n−2)
这个东西可以矩乘,也可以用特征根求通项。
r2=(o−2)r+(o−1)
解出来r1=−1,r2=d−1
然后f(n)=c1∗r1n+c2∗r2n
可以把f(1)=0,f(2)=d∗(d−1)带入就可以求出c1,c2
解得c1=d−1,c2=1
f(n)=(d−1)(−1)n+(d−1)n
#include<iostream> #include<algorithm> #include<cstring> #include<cmath> #include<cstdio> #define base 3214567 #define ll long long using namespace std; ll n,m,r,ans; ll read() { ll x=0,f=1; char ch; while (ch=getchar(),ch<'0'||ch>'9') if (ch=='-') f=-1; while (x=x*10+ch-'0',ch=getchar(),ch>='0'&&ch<='9'); return x*f; } ll gcd(ll a,ll b){return b?gcd(b,a%b):a; } ll ksm(ll x,ll k){ ll res=1; for (ll i=k; i; i>>=1,x=1ll*x*x%base) if (i&1) res=1ll*res*x%base; return res; } ll phi(ll x) { ll res=x; for (int i=2; i<=sqrt(x); i++) { if (x%i==0) {while (x%i==0) x/=i; res=res*(i-1)/i;} } if (x!=1) res=res*(x-1)/x; return res; } ll get(ll N,ll M) { ll ans=0; //for (int i=1; i<=N; i++) ans=(ans+ksm(M,gcd(N,i)))%base; for (ll i=1; i*i<=N; i++) if (N%i==0) ans=((ans+phi(N/i)*ksm(M,i))%base+((i*i!=N)?phi(i)*ksm(M,N/i):0))%base; return ans; } ll get2(ll N,ll M) { //cout<<" "<<N<<" "<<M<<endl; ll ans=0; //ans=ksm(M,N+(gcd(N,i)%2)?1-M:M-1)); ans=(ksm(M-1,N)+(N%2==0?M-1:1-M))%base; return ans; } int main() { n=read(); m=read(); r=read(); m=get(m,r)*ksm(m,base-2)%base; // cout<<m<<endl; ans=get2(n,m); printf("%d ",ans); return 0; }