首先,要求有多少种不同的项链,需要先求出有多少种不同的戒指
m个彩色球状物,旋转后相同视为相同,R种颜色,是不是很眼熟(然而并不,为什么我看题的时候想的是可重复圆排...),没错这就是置换
首先由burnside引理得种类数
num=∑mi=1cim
(
ci
表示第i种置换下相同的方案数),
然后由polya得,
num=∑mi=1Rgcd(i,m)m
关于为什么旋转i次下的置换的环有
gcd(i,m)
个,是易证的我知道写易证会被人打死
那就证一下吧
设
d=gcd(i,m)
将戒指铺在数轴上,每m个为一个循环节,一个位置x不断往后跳i个位置,跳到一个位置y满足
y≡x(Mod m)
,一定有
y−x=lcm(i,m)
,那么他在跳的过程中覆盖到了
lcm(i,m)i=md
个位置,这些位置在
Mod m
下互不相同且组成了一个置换环,每个置换环都有
md
个元素,那么一共就有
mmd=d
个置换环
证毕
考虑怎么求
∑mi=1Rgcd(i,m)
推一下柿子
∑mi=1Rgcd(i,m)−>
∑d|mRd∑mdi=1,(i,md)=11−>
∑d|mRdφ(md)
预处理一下
φ
,当
md
超过预处理的范围时可以
O(n√)
枚举,分解质因数,也可以预处理
m
的质因数,
对了对了,大家有没有注意到模数
因为
m<p2
,所以
mp<p
,有逆元,因为答案是个整数,所以分子一定是
p
的倍数,我们可以分子分母同除一个
然后我们终于算粗了
num
考虑算项链的种类
这个特殊纪念品的作用其实就是将环剖成了链,不让我们再算一次置换
那么设
f[i][0],f[i][1]
表示长度为i的项链,第i个戒指和第一个戒指是否相同(0表示不同,1表示相同),项链的种类数
有
f[i][0]=f[i−1][1]∗(num−1)+f[i−1][0]∗(num−2),f[i][1]=f[i−1][0]
这个东西可以用矩乘
然后…没了吧…
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const ll Mod = 3214567;
const int maxn = 1e6+10;
ll n,m,R,num;
int p[maxn],pri,phi[maxn];
bool v[maxn];
void pre()
{
phi[1]=1;
for(int i=2;i<maxn;i++)
{
if(!v[i]) phi[p[++pri]=i]=i-1;
for(int j=1;j<=pri;j++)
{
int k=i*p[j];
if(k>=maxn) break;
v[k]=true;
if(i%p[j]==0)
{
phi[k]=phi[i]*p[j];
break;
}
phi[k]=phi[i]*phi[p[j]];
}
}
}
int Mp[maxn],Mn;
void get_mp()
{
ll k=m;
for(int i=1;p[i]*p[i]<=k;i++) if(k%p[i]==0)
{
Mp[++Mn]=p[i];
while(k%p[i]==0) k/=p[i];
}
if(k>1) Mp[++Mn]=k;
}
ll pw(const ll x,int k,ll M)
{
ll ret=1ll;
for(ll tmp=x%M;k;k>>=1,tmp=tmp*tmp%M)
if(k&1) ret=ret*tmp%M;
return ret;
}
ll N(const ll x,ll M) {return pw(x,M-2,M);}
int get_phi(int x)
{
if(x<maxn) return phi[x];
int r=1;
for(int i=1;i<=Mn&&x!=1;i++) if(x%Mp[i]==0)
{
x/=Mp[i];
r*=Mp[i]-1;
while(x%Mp[i]==0) x/=Mp[i],r=r*Mp[i];
}
return r;
}
void get_num()
{
ll M=m%Mod==0?Mod*Mod:Mod,r=0;
int qm=sqrt(m);
for(int i=1;i<=qm;i++) if(m%i==0)
{
ll t=pw(R,i,M)*(get_phi(m/i)%M)%M;
(r+=t)%=M;
if(i*i==m) break;
t=pw(R,m/i,M)*(get_phi(i)%M)%M;
(r+=t)%=M;
}
r%=M;
if(m%Mod==0) ((r/=Mod)*=N(m/Mod,Mod))%=Mod;
else (r*=N(m,Mod))%=Mod;
num=r;
}
struct Matrix
{
ll a[2][2];
Matrix(){a[0][0]=a[0][1]=a[1][0]=a[1][1]=0ll;}
}one,st,g;
inline Matrix operator *(Matrix &x,Matrix &y)
{
Matrix ret;
for(int i=0;i<2;i++)
{
for(int k=0;k<2;k++)
for(int j=0;j<2;j++)
(ret.a[i][j]+=x.a[i][k]*y.a[k][j]%Mod)%=Mod;
}
return ret;
}
ll solve()
{
ll k=n-1;
g.a[0][1]=num;
Matrix f=st;
for(;k;k>>=1,f=f*f)
if(k&1) g=g*f;
return g.a[0][0];
}
int main()
{
pre();
one.a[0][0]=one.a[1][1]=1ll;
scanf("%lld%lld%lld",&n,&m,&R);
get_mp();
get_num();
st.a[0][1]=1ll,st.a[0][0]=num-2;
st.a[1][0]=num-1;
printf("%lld\n",solve());
return 0;
}