COMPFEST 13 Finals Online Mirror, cf-1575G. GCD Festival 题解
题意
给定一个n长度的数组a,要你计算
思路
莫比乌斯反演(其实我觉得这里叫欧拉反演更合适些)
代入原式
这里更换贡献计算顺序,枚举d来叠加答案的贡献
不过,在此之前,我们先约定一个符号
for(int i=d;i<=n;i+=d)
下面继续计算答案
同理,我们枚举因子
其中,
公式推导如下
个人感觉写的有点赘余,每一步都只有一小步的化简,但是考虑到数学公式的难以理解,还是写的很冗长,还望和我一样的初学者看的更明白些
(公式中,
好了,到这里,我们就可以考虑如何枚举
代码
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
const i64 MOD = 1e9+7;
const int MX = 1e5+6;
vector<int> ph(MX);
vector<int> d[MX];
void get_phi() {
for(int i=0;i<MX;++i) {
ph[i] = i;
}
for(int i=2;i<MX;++i) {
if(ph[i]==i)
for(int j=i;j<MX;j+=i) {
ph[j] -= ph[j]/i;
}
}
}
void get_divisor() {
for(int i=1;i<MX;++i) {
for(int j=i;j<MX;j+=i) {
d[j].push_back(i);
}
}
}
int main(int argc, char const *argv[])
{
ios_base::sync_with_stdio(false);
cin.tie(nullptr); cout.tie(nullptr);
get_phi();
get_divisor();
int n;
cin >> n;
vector<i64> a(n+1);
for(int i=1;i<=n;++i) {
cin >> a[i];
}
i64 ans = 0;
vector<int> cnt(MX);
for(int i=1;i<=n;++i) {
i64 s1=0;
for(int j=i;j<=n;j+=i) {
for(int e : d[a[j]]) {
++cnt[e];
}
}
for(int j=i;j<=n;j+=i) {
for(int e : d[a[j]]) {
if(cnt[e]) {
i64 s2=cnt[e];
cnt[e] = 0;
s2 *= s2;
s2 %= MOD;
s2 *= ph[e];
s2 %= MOD;
s1 += s2;
s1 %= MOD;
}
}
}
ans += ph[i] * s1;
ans %= MOD;
}
cout << ans;
return 0;
}
Living with bustle, hearing of isolation.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!