51nod 1675.序列变换

序列变换

题目描述

\(lyk\) 有两序列 \(a\)\(b\)
\(lyk\) 想知道存在多少对 \(x,y\),满足以下两个条件。
\(1:\gcd(x,y)=1\)
\(2:a_{b_x} = b_{a_y}\)
例如若 \(a={1,1,1},b={1,1,1}\)。那么存在 \(7\) 对,因为除了 \(x=2,y=2\)\(x=3,y=3\) 外都满足条件。

输入

第一行一个数 \(n(1<=n<=100000)\)
接下来一行n个数,表示 \(ai(1<=ai<=n)\)
接下来一行n个数,表示 \(bi(1<=bi<=n)\)

输出

一行表示答案

输入样例

3
1 1 1
1 1 1

输出样例

7

解析

这是我第一次用莫比乌斯反演性质二的第一题
先打出莫比乌斯反演性质二:
有数论函数 \(f(n)= \sum_{d|n} g(d)\)
逆求 \(g(n)\)
则有:
\[ g(n)=\sum_{d|n} f(d) \mu(\frac{n}{d}) \]
日后再证

然后套路解题

\[ f(x) = \sum_{i=1}^n \sum_{j=1}^n [\gcd(i,j)=x][a_{b_x} = b_{a_y}] \]
再设
\[ F(x)=\sum_{x|d} f(d) \]

然后玩第二个式子
\[ \begin{aligned} F(x) &=\sum_{x|d} f(d) \\ &=\sum_{x|d} \sum_{i=1}^n \sum_{j=1}^n [\gcd(i,j)=d][a_{b_x} = b_{a_y}] \\ &=\sum_{i=1}^n \sum_{j=1}^n [x|gcd(i,j)][a_{b_x} = b_{a_y}] \\ &=\sum_{x|i} \sum_{x|j} [a_{b_x} = b_{a_y}] \end{aligned} \]
那么,答案就是:
\[ f(1) = \sum_{i=1}^n F(i) \mu(i) \]

\(f(1)\) 我们期望是 \(O(n)\)
所以我们要预处理出 \(\mu\) 和所有 \(F(i)\)
如何快速计算 \(F(i)\)
呵呵,先开个桶,然后~~~
看我代码吧,政治觉悟略高的同志必然能看得懂

代码

#include<cstdio> 
using namespace std;
typedef long long LL;

const int N = 1e5;
int a[N + 5] , b[N + 5] , n , mu[N + 5] , tot , prime[N + 5] , vis[N + 5];
LL cnt[N + 5] , F[N + 5] , ans;

inline void getF()
{
    for(register int i = 1; i <=n; i++)
    {
        for(register int j = i; j <= n; j += i) cnt[a[b[j]]]++;
        for(register int j = i; j <= n; j += i) F[i] += cnt[b[a[j]]];
        for(register int j = i; j <= n; j += i) cnt[a[b[j]]]--;
    }
}

inline void getmu()
{
    mu[1] = 1;
    for(register int i = 2; i <=n; i++)
    {
        if (!vis[i]) mu[prime[++tot] = i] = -1;
        for(register int j = 1; j <= tot && prime[j] * i <= n; j++)
        {
            vis[prime[j] * i] = 1;
            if (i % prime[j] == 0) break;
            mu[prime[j] * i] = -mu[i];
        }
    }
}

int main()
{
    scanf("%d" , &n);
    for(register int i = 1; i <= n; i++) scanf("%d" , &a[i]);
    for(register int i = 1; i <= n; i++) scanf("%d" , &b[i]);
    getF() , getmu();
    for(register int i = 1; i <= n; i++) ans += (LL)mu[i] * F[i];
    printf("%lld" , ans);
}

猜你喜欢

转载自www.cnblogs.com/leiyuanze/p/12183208.html