序列

题面描述

题解

\([condition]= \begin{cases} 1 & \text{if condition 成立}\\ 0& \text{if condition 不成立} \end{cases}\)

\(ans=\sum_{1\leq x,y\leq n}[a_{b_x}=b_{a_y}][gcd(x,y)=1]\)

显然这题如果没有条件\(gcd(x,y)=1\),便可以\(O(n)\)求出答案
而如果只是找\(gcd(x,y)=1\)则需要\(O(n^2)\)

那么可以尝试用一用容斥的思想,先尝试求出\(gcd(x,y)\)包含约数d的解,再看看是否能继续下去
\(\:\:\: f(d)=\sum_{1\leq x,y\leq n}[a_{b_x}=b_{a_y}][gcd(x,y)=d]\)
\(\:\: \: g(d)=\sum_{d|d'}f(d')=\sum_{d|x,d|y}[a_{b_x}=b_{a_y}]\)
显然\(g(d)=\sum_{d|x,d|y}[a_{b_x}=b_{a_y}]\)便可以用\(O(\frac{n}{1}+\frac{n}{2}+···+\frac{n}{n}=nlnn)\)求出

再仔细观察\(g(d)=\sum_{d|d'}f(d')\),明显符合莫比乌斯反演定理
\(\:\:\: f(d)=\sum_{d|d'}\mu(\frac{d'}{d})g(d')\)
\(ans=f(1)=\sum_{i=1}^{n}\mu(i)g(i)\)

点击查看代码
#include<functional>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<deque>
#define ll long long 
using namespace std;
const int maxn=1e5+101;
const int MOD=1e9+7;
const int inf=2147483647;
int read(){
    int x=0,f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
    return x*f;
}
int mu[maxn];
int tot,is[maxn],prime[maxn];
int n,a[maxn],b[maxn],cnt[maxn];
ll g[maxn];
void get_mu(){
    mu[1]=1;
    for(int i=2;i<=n;i++){
        if(!is[i])prime[++tot]=i,mu[i]=-1;
        for(int j=1;j<=tot && prime[j]<=n/i;j++){
            is[i*prime[j]]=1;
            if(i%prime[j]==0)break;
            mu[i*prime[j]]=-mu[i];
        }
    }
}
int main(){
    n=read();get_mu();
    for(int i=1;i<=n;i++)a[i]=read();
    for(int i=1;i<=n;i++)b[i]=read();
    for(int i=1;i<=n;i++){
        for(int j=i;j<=n;j+=i)cnt[a[b[j]]]++;
        for(int j=i;j<=n;j+=i)g[i]+=cnt[b[a[j]]];
        memset(cnt,0,sizeof(cnt));
    }
    ll ans=0;
    for(int i=1;i<=n;i++)ans+=mu[i]*g[i];
    printf("%lld",ans);
    return 0;
}
posted @ 2021-11-02 23:48  I_N_V  阅读(29)  评论(0编辑  收藏  举报