您的位置:首页 > 其它

51Nod - 1675 序列变换 mobius反演

2017-10-14 12:03 295 查看
题意:

lyk有两序列a和b。

lyk想知道存在多少对x,y,满足以下两个条件。

1:gcd(x,y)=1。

2: abx=bay 。

例如若a={1,1,1},b={1,1,1}。那么存在7对,因为除了x=2,y=2或x=3,y=3外都满足条件。

Input

第一行一个数n(1<=n<=100000)。

接下来一行n个数,表示ai(1<=ai<=n)。

接下来一行n个数,表示bi(1<=bi<=n)。

思路:

只是增加了 abx=bay好像就不太会处理了。

考虑mobius反演的第二种形式,这里就不再赘述了.

F(d) 表示gcd == d 的倍数有多少.因为这里的gcd 是指的下标,所以我们每次枚举的是下标的gcd,然后将下标满足gcd条件的abx 加入num数组计数,在同样枚举 bay 计数就好了,这样就求出了F(d)。

#include<bits/stdc++.h>

using namespace std;
const int maxn = 1e5+5;
typedef long long ll;
int prime[maxn],mu[maxn];
int a[maxn],b[maxn],num[maxn],n;
bool vis[maxn];
void mobius()
{
int cnt = 0;
mu[1] = 1;
for(int i =2;i < maxn;++i)
{
if(!vis[i])
prime[++cnt] = i,mu[i] = -1;
for(int j = 1;(ll)prime[j]*i < maxn;++j)
{
vis[i*prime[j]] = 1;
if(i%prime[j] == 0)
{
mu[i*prime[j]] = 0;
break;
}
mu[i*prime[j]] = -mu[i];
}
}
return ;
}
ll solve(int d)
{
for(int i = d;i <= n;i += d)
num[a[b[i]]]++;
ll res = 0;
for(int i = d;i <= n;i += d)
res += num[b[a[i]]];
for(int i = d;i <= n;i += d)
num[a[b[i]]]--;
return res;
}
int main()
{
mobius();
while(~scanf("%d",&n))
{
for(int i = 1;i <= n;++i)
scanf("%d",&a[i]),num[i] = 0;
for(int i = 1;i <= n;++i)
scanf("%d",&b[i]);
ll ans = 0;
for(int i = 1;i <= n;++i)
if(mu[i])
ans += (ll)mu[i]*solve(i);
printf("%I64d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: