E-Exclusive Multiplication_“统信杯” 第十七届黑龙江省大学生程序设计竞赛(正式赛) (nowcoder.com)
题意:设一个整数n,,定义,
现在给你一个长度为n的序列b,问
知识点:莫比乌斯反演
思路:
首先,我们先想办法把俩下标都改成从1开始到n,
现在我们的问题是求(1),(2)
然后,我们开始看f函数,容易发现
所以,.
,
接下来是套路化的东西,我们定义,为i的个数
枚举d
莫反,枚举T
设Q=dT,枚举Q
定义,
我们可以暴力预处理,整体复杂度是(d(i)表示i的约数个数),在m=2e5时为16782730,肯定是够的,所以就出来了,关于f(i),我们直接O(n)预处理就可以了,具体可以看代码
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 2e5+5;
const ll mod =1e9+7;
ll p[N],cnt,f[N],u[N],g[N];
bool v[N],low[N];//low(i)表示i的最小质数的个数
void init(){
u[1]=1;f[1]=1;
for(ll i=2;i<N;++i){
if(!v[i])p[cnt++]=i,u[i]=-1,f[i]=i,low[i]=1;//质数是f(i)=i,low(i)=1
for(ll j=0;j<cnt&&i*p[j]<N;++j){
v[i*p[j]]=true;
ll now=i*p[j];
if(i%p[j]==0){//如果i和p[j]不互质
//i的最小质数个数是奇数,再+1肯定是偶数,把p[j]消去
if(low[i]&1)f[now]=f[i]/p[j];
else f[now]=f[i]*p[j];
//i的最小质数个数是偶数,再+1肯定是奇数,把p[j]乘进去
low[now]=low[i]^1;//个数变一下
break;
}
f[now]=f[i]*p[j];//互质直接乘
low[now]=1;//最小质数个数肯定是1
u[now]=-u[i];
}
}
}
ll n,b,has[N],maxx;
void solve(){
cin>>n;
for(int i=1;i<=n;++i){
cin>>b;
has[b]++;//定义
maxx=max(maxx,b);
}
ll ans=0;
for(ll i=1;i<=maxx;++i){
for(ll j=i;j<=maxx;j+=i){//i是j的因子
ll res=0;
for(ll w=1;w<=(maxx/j);++w)res=(res+f[i*w]*has[j*w]%mod)%mod;//式子
res=res*res%mod;
g[j]=(g[j]+u[i]*res%mod+mod)%mod;//式子
}
ans=(ans+g[i])%mod;//累加
}
ll inv2=(mod+1)/2;//记得是模意义下
ans=(ans-n+mod)%mod*inv2%mod;
cout<<ans<<'\n';//答案
}
int main() {
init();
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
int _=1;//cin>>_;
while(_--){
solve();
}
return 0;
}
/*
*/