题目传送门:洛谷P3307。这题在bzoj上是权限题。

题意简述:

这题分为两个部分:

① 有一些珠子,每个珠子可以看成一个无序三元组。三元组要满足三个数都在$1$到$m$之间,并且三个数互质,两个珠子不同当且仅当这个三元组不同。计算有多少种不同的珠子。

② 把这些珠子串成一个环,要满足相邻的珠子不同。两个环不同当且仅当旋转任意角度后仍然不同。计算有多少种不同的环。

题解:

分成两部分做。

第一部分:

考虑计算三元组的个数,转无序为有序,再去重。

答案=(三个都不同的有序三元组方案)/6+(两个相同,另一个不同的方案)/3+(三个都相同的方案)。

容斥一下得到答案=(三元组的方案+二元组的方案*3+一元组的方案*2)/6。

因为一元组只有(1)满足条件,所以答案是(2+三元组的方案+二元组的方案*3)/6。

考虑如何求出两种方案。

三元组的方案是\(\sum_{i=1}^m\sum_{j=1}^m\sum_{k=1}^m[\gcd(i,j,k)=1]\),二元组同理。

显然是莫反套路,三元组的答案是\(\sum_{d=1}^m\mu(d){\left\lfloor\frac{m}{d}\right\rfloor}^3\),二元组同理。

数论分块求出答案即可,最后乘上6的逆元。这一步复杂度$\Theta(m+T\sqrt{m})$。

第二部分:

知道了不同珠子的数量,要求出本质不同的环的个数。

Burnside引理套路。最终方案数等于每个置换的不动点个数的平均数,即\(\frac{1}{n}\sum_{i=1}^nf(i)\),\(f(i)\)表示旋转\(i\)格的不动点数量。

稍微化简一下:\(\frac{1}{n}\sum_{d|n}\varphi(\frac{n}{d})f(d)\)。

考虑计算\(f(x)\),当$x$是$n$的因数时,$f(x)$就等于不考虑旋转时的长度为$x$的环的数量。

假设不同珠子的数量为\(k\),不加证明地给出一个式子:\(f(x)=(k-1)^x+(-1)^x(k-1)\)。这个式子可以递推得出。

那么根据这个式子和上面的式子计算即可。

要注意\(n\)太大了,要求出\(\varphi\)的值比较困难,考虑DFS它的每个质因数,按照\(\varphi\)是个积性函数以及公式,求得\(\varphi\)。

要注意,最后除掉\(n\)的时候,\(n\)可能是模数的倍数导致没有逆元。可以发现\(n\)不会是模数平方的倍数,所以把模数平方后再做一遍,最后除掉模数这个因子即可。

 #include <cstdio>

 #define reg register
typedef unsigned long long ULL;
const ULL MOD = 1000000007ll;
const ULL Inv61 = 166666668ll;
const ULL Inv62 = 833333345000000041ll;
ULL Mod;
ULL Inv6;
const int MN = ; ULL TN[];
int TA[], MA; bool ip[MN];
int p[MN], pc;
int mu[MN];
inline void SieveInit() {
ip[] = ip[] = ;
mu[] = ;
for (reg int i = ; i <= MA; ++i) {
if (!ip[i])
p[++pc] = i,
mu[i] = -;
for (reg int j = ; j <= pc; ++j) {
reg int k = p[j] * i;
if (k > MA) break;
ip[k] = ;
if (i % p[j]) mu[k] = -mu[i];
else break;
}
}
for (reg int i = ; i <= MA; ++i)
mu[i] += mu[i - ];
} int O;
inline ULL Mul(ULL x, ULL y) {
if (!O) return x * y % Mod;
return (x * y - (ULL)((long double) x / Mod * y) * Mod + Mod) % Mod;
} ULL N; int A;
ULL M;
inline void SolveM() {
M = ;
for (reg int i = , j, k; i <= A; i = j + ) {
k = A / i, j = A / k;
M = (M + Mul(Mul(Mul(k, k), k + ), (mu[j] - mu[i - ] + Mod) % Mod)) % Mod;
}
M = Mul(M, Inv6);
} ULL Pow[];
inline void PowInit() {
Pow[] = M - ;
for (reg int i = ; i < ; ++i) Pow[i] = Mul(Pow[i - ], Pow[i - ]);
}
inline ULL qPow(ULL E) {
ULL A = ;
for (reg int j = ; E; E >>= , ++j)
if (E & ) A = Mul(A, Pow[j]);
return A;
}
inline ULL Inv(ULL B) {
ULL A = ;
for (reg ULL E = MOD - ; E; E >>= , B = B * B % MOD)
if (E & ) A = A * B % MOD;
return A;
} ULL b[]; int e[], cnt;
ULL Ans;
inline ULL F(ULL x) {
return (qPow(x) + (x & ? Mod - M + : M - )) % Mod;
}
void DFS(int st, ULL now, ULL phi) {
if (st > cnt) {
Ans = (Ans + Mul(phi % Mod, F(N / now))) % Mod;
return;
}
DFS(st + , now, phi);
for (reg int i = ; i <= e[st]; ++i) {
now *= b[st];
phi *= i == ? b[st] - : b[st];
DFS(st + , now, phi);
}
}
inline ULL Solve() {
ULL NN = N; cnt = ;
for (reg ULL i = ; i * i <= NN; ++i) if (NN % i == ) {
b[++cnt] = i, e[cnt] = ;
while (NN % i == ) NN /= i, ++e[cnt];
} if (NN > ) b[++cnt] = NN, e[cnt] = ;
Ans = ; DFS(, , );
if (O) Ans = Ans / MOD * Inv(N / MOD) % MOD;
else Ans = Ans * Inv(N % MOD) % MOD;
return Ans;
} int main() {
int Tests;
scanf("%d", &Tests);
for (int i = ; i <= Tests; ++i)
scanf("%llu%d", TN + i, TA + i),
MA = TA[i] > MA ? TA[i] : MA;
SieveInit();
for (int i = ; i <= Tests; ++i) {
N = TN[i], A = TA[i];
O = N % MOD ? : ;
if (O) Mod = MOD * MOD, Inv6 = Inv62;
else Mod = MOD, Inv6 = Inv61;
SolveM();
PowInit();
printf("%llu\n", Solve());
}
return ;
} // 1. 求出本质不同的珠子数量,容斥 + 莫比乌斯反演 + 数论分块
// 2. 求出答案,Burnside 引理 + 数论分块

最新文章

  1. vim - multiple windows
  2. java 判断某一天是当年的哪一天
  3. 【BZOJ 2809】 [Apio2012]dispatching
  4. javascript 在一个函数参数中包含另一个函数的引用
  5. C#语句及案例
  6. 在Objective-C声明Block的几种方式
  7. Delphi-Copy 函数
  8. sublime Text3+emmet(快速开发)
  9. Python安装与环境变量
  10. 后缀html和htm文件的区别
  11. okHttp超时报错解决方案
  12. 微信分享链接出现config:invalid signature错误的解决方法
  13. LeetCode(125):验证回文串
  14. vue-cli脚手架之package.json
  15. vue用组件构建应用
  16. Django:视图views(三)
  17. 9 tips to improve spoken english
  18. 设置 sideload Outlook Add-ins
  19. Python基础5 常用模块学习
  20. Vue 2.0 pagination分页组件

热门文章

  1. Opera官网打不开 下载Opera最新版本的实际地址
  2. UVALive6442_Coins on a Ring
  3. Python学习---日期时间
  4. P2461 [SDOI2008]递归数列
  5. P1155 双栈排序
  6. Android App Architecture使用详解
  7. elasticsearch5使用snapshot接口备份索引
  8. Android listview与adapter用法(BaseAdapter + getView)
  9. LGP4577【JSOI2018】战争
  10. codeforces div1 &amp; div2 参与人员分数统计