我已经是一个啥都学不懂的人了
由于别人的博客都比较好,所以我就直接搬了一些了
1.置换。
大概学过抽象代数的同学都知道这个概念吧。
置换简单来说就是对元素进行重排列,如下图所示。置换是[1,n]到[1,n]的一一映射。
再比如,将正方形绕其中心逆时针旋转90度,可以看成是正方形四个顶点的一个置换。关于置换、置换群的具体理论,可以学一下抽象代数。
(1)置换可以分解成若干循环,方法为:连边
1
−
>
a
1
,
2
−
>
a
2
,
…
,
i
−
>
a
i
,
…
,
n
−
>
a
n
1−>a1,2−>a2,…,i−>ai,…,n−>an
1−>a1,2−>a2,…,i−>ai,…,n−>an,任取一个元素,顺着有向边走,直到回到出发点,即形成一个环,剩余元素也是这样。
(2)如果一个状态经过置换f后跟原来相同,即
S
[
1
]
=
S
[
a
1
]
,
S
[
2
]
=
S
[
a
2
]
,
…
,
S
[
n
]
=
S
[
a
n
]
S[1]=S[a1],S[2]=S[a2],…,S[n]=S[an]
S[1]=S[a1],S[2]=S[a2],…,S[n]=S[an]。则称该状态为f 的不动点。
(3)题目中常常出现“本质不同的方案数”,一般是指等价类的数目,题目定义一个等价关系,满足等价关系的元素属于同一等价类。等价关系通常是一个置换集合
F
F
F,如果一个置换能把其中一个方案映射到另一个方案,则二者是等价的。
那么,置换构成的群就是置换群,就是交换排列顺序而已。
那么这里介绍一个 B u r n s i d e Burnside Burnside引理
对于一个置换 f f f,若一个染色方案 s s s经过置换后不变,称 s s s为 f f f的不动点。将 f f f的不动点数目记为 C ( f ) C(f) C(f),则可以证明等价类数目为所有 C ( f ) C(f) C(f)的平均值。
换句话说,我们是要所有不同的段之间的对应位置相同(其实也就是形成一个轮换)
举个例子,比如说,对于一个 2 × 2 2\times 2 2×2的矩形,他有四种置换,分别是旋转90°,180°,270°和0°,而对于这四种,对于90°,他就相当于四个块(每90°一块)的对应位置是相同的,那就是我们有两种染法(因为每一块就一个矩形,而只有染和不染两种选择。)
那么同理 180°是4种,0°是16种,270°也是2种
那么最终的 a n s = 2 + 2 + 4 + 16 4 = 6 ans = \frac{2+2+4+16}{4} = 6 ans=42+2+4+16=6
那么6就是我们最后要求的答案了。
那么有一个例题 T73176 秘籍-反复迷宫
23333
具体可以去洛谷团队——硫代硫酸钠纠察大队 里面看题面
这个题的话就是一个
b
u
r
n
s
i
d
e
burnside
burnside引理的好题。
考虑正方形,假设我们已经通过递推得到了图形含有的总边数
s
u
m
sum
sum,那么考虑四边形的置换存在四种,那么我们分情况讨论,首先是
90
°
90°
90°,由于我们在用
b
u
r
n
s
i
d
e
burnside
burnside的时候规定了每一个对应位置都是相等的,也就是说,我们这一段和剩下所有的段都相等,方案数就是
C
n
/
4
r
/
4
C_{n/4}^{r/4}
Cn/4r/4,相当于划分成完全相同的四份,然后从一份中选出来
r
/
4
r/4
r/4(因为剩下都一样)。
这里需要注意的是,由于要是完全相同,所以
r
r
r要是
4
4
4的倍数,剩下的也是同理,这里就不多介绍。
六边形也是一样的道理
那么我们会发现,这些栗子的共性就是只有染色和不染色两种情况。
那如果有颜色该怎么办呢?
这时候就需要 P o l y a Polya Polya定理
考虑每一个循环本身的颜色要求相同,但是互相之间却没有要求
比如说
6
个
数
组
成
的
环
6个数组成的环
6个数组成的环,那么可以构成
(
1
,
4
)
(
2
,
5
)
(
3
,
6
)
(1,4)(2,5)(3,6)
(1,4)(2,5)(3,6)这样的循环,两两之间没有限制的,那么我们会发现,实际上贡献就是
m
k
m^k
mk,m是颜色数,k是这样的循环数。
回到洛谷4980这个题的话,我们经过推理(目前我所理解的最好理解的版本)
可以看出来,那么对于一个置换他的段数就是
n
/
(
l
c
m
(
n
,
i
)
/
i
)
n/(lcm(n,i)/i)
n/(lcm(n,i)/i),原因同上。
那么也就是 g c d ( i , n ) gcd(i,n) gcd(i,n)
那么问题就转化成了求
∑
i
=
1
n
n
g
c
d
(
i
,
n
)
\sum_{i=1}^n n ^{gcd(i,n)}
∑i=1nngcd(i,n)
推一波柿子
a
n
s
=
∑
d
∣
n
n
d
∑
i
=
1
n
[
g
c
d
(
i
,
n
)
=
=
d
]
ans = \sum_{d|n} n^d \sum_{i=1}^n[gcd(i,n)==d]
ans=d∣n∑ndi=1∑n[gcd(i,n)==d]
a
n
s
=
∑
d
∣
n
n
d
∑
i
=
1
n
d
[
g
c
d
(
i
,
n
d
)
=
=
1
]
ans =\sum_{d|n} n^d \sum_{i=1}^{\frac{n}{d}}[gcd(i,\frac{n}{d})==1]
ans=d∣n∑ndi=1∑dn[gcd(i,dn)==1]
a
n
s
=
∑
d
∣
n
n
d
×
ϕ
(
n
d
)
ans = \sum_{d|n} n ^d \times \phi(\frac{n}{d})
ans=d∣n∑nd×ϕ(dn)
那么我们可以对于每一个因数都是用 O ( n ) O(\sqrt n) O(n)的时间复杂度求出来 p h i phi phi
然后就可以解决这个题了
// luogu-judger-enable-o2
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<map>
#include<set>
#include<cstdlib>
#define ll long long
#define pb push_back
#define mk make_pair
#define lson ch[x][0]
#define rson ch[x][1]
#define int long long
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
const int mod = 1e9+7;
int n,t;
int getphi(int x)
{
if (x==1) return 1;
int tmp = x;
int xx = x;
for (int i=2;i*i<=xx;i++)
{
if (x%i==0)
{
tmp=tmp/i*(i-1);
while(x%i==0) x/=i;
}
}
if (x>1) tmp=tmp/x*(x-1);
return tmp;
}
int qsm(int i,int j)
{
int ans=1;
while (j)
{
if (j&1) ans=ans*i%mod;
i=i*i%mod;
j>>=1;
}
return ans;
}
signed main()
{
t=read();
while (t--)
{
n=read();
int ans=0;
for (int i=1;i*i<=n;i++)
{
if (n%i==0)
{
ans=(ans+qsm(n,i)*getphi(n/i)%mod)%mod;
if (i*i!=n) ans=(ans+qsm(n,n/i)*getphi(i)%mod)%mod;
}
}
cout<<ans*qsm(n,mod-2)%mod<<"\n";
}
return 0;
}