给定一个(n)个点,(n)条边的环,有(n)种颜色,给每个顶点染色,问有多少种本质不同的染色方案,答案对(10^9+7)取模
注意本题的本质不同,定义为:只需要不能通过旋转与别的染色方案相同。
一种染色方案可以看做先染了前(d)个位置,然后将这一段复制(frac{n}{d})次拼接而成,其中(d|n)。我们称这个(d)为一种染色方案的周期(这里默认是最小正周期)。
对于一个周期(循环个数)为(d)的染色方案,将它旋转(d)次会得到(d)个看起来不同但本质相同的染色方案。
设(f(x))表示周期为(x)的看上去不同的方案数。枚举周期(d),那么每一种周期的方案就多算(d)次,因此(ans=sumlimits_{d|n}dfrac{f(d)}{d})
(f(x))不容易计算,但是我们知道:对于(n)的所有约数(d),将(f(d))求和就会得到总方案数(m^n),即
[m^n=sumlimits_{d|n}f(d)
]
莫比乌斯反演得
[f(x)=sumlimits_{d|x}mu(frac{n}{d})m^d
]
代入第一个式子得到
[ans=sumlimits_{d|n}frac{1}{d}sumlimits_{k|d}mu(frac{d}{k})m^k
]
[=sumlimits_{d|n}frac{d}{n}sumlimits_{k|frac{n}{d}}mu(frac{n}{dk})m^k
]
[=frac{1}{n}sumlimits_{d|n}dsumlimits_{k|frac{n}{d}}mu(frac{n}{dk})m^k
]
[=frac{1}{n}sumlimits_{k|n}m^ksumlimits_{d|frac{n}{k}}dmu(frac{n}{dk})
]
[=frac{1}{n}sumlimits_{k|n}m^kvarphi(n/k)
]
上面设颜色的数量为(m)是为了避免混淆,本题中(m=n)。
Code
#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
int t, n, m;
unordered_map < int, int > fphi;
int read()
{
int x = 0, fl = 1; char ch = getchar();
while (ch < '0' || ch > '9') { if (ch == '-') fl = -1; ch = getchar();}
while (ch >= '0' && ch <= '9') {x = x * 10ll + ch - '0'; ch = getchar();}
return x * fl;
}
int qpow(int base, int pw)
{
int s = 1;
while (pw)
{
if (pw & 1) s = 1ll * s * base % mod;
base = 1ll * base * base % mod;
pw >>= 1;
}
return s;
}
int phi(int x)
{
if (fphi[x]) return fphi[x];
int t = x, y = x;
for (int i = 2; i <= m; i ++ )
{
if ((x % i) == 0)
{
t = t / i * (i - 1);
while ((x % i) == 0) x /= i;
}
}
if (x > 1) t = t / x * (x - 1);
return fphi[y] = t;
}
int main()
{
t = read();
while (t -- )
{
n = read(), m = (int)(sqrt(n));
int res = 0;
for (int k = 1; k <= m; k ++ )
{
if (n % k) continue;
res = (res + 1ll * qpow(n, k) * phi(n / k) % mod) % mod;
if (k * k != n) res = (res + 1ll * qpow(n, n / k) * phi(k) % mod) % mod;
}
res = 1ll * res * qpow(n, mod - 2) % mod;
printf("%d
", res);
}
return 0;
}