您的位置:首页 > 其它

51Nod-1594-Gcd and Phi

2017-09-05 13:29 411 查看
ACM模版

描述



题解

这个题更准确的描述应该是求 F(n)=∑i=1n∑j=1nϕgcd(ϕi,ϕj) 首先我们可以设 s[i] 表示 1∼n 中欧拉函数等于 i 的数有多少个。那么我们可以得到:F(n)=∑d=1n∑i=1⌊nd⌋∑j=1⌊nd⌋ϕd∗s[id]∗s[jd][gcd(i,j)=1] 此时,反演可以上了。

设 g(d)=∑i=1⌊nd⌋∑j=1⌊nd⌋s[id]∗s[jd][gcd(i,j)=1] f(d)=∑k=1⌊nd⌋g(kd) 所以 f(d)=∑i=1⌊nd⌋∑j=1⌊nd⌋s[id]∗s[jd] 这里的 f 数组预处理一下即可。

所以由于 g(d)=∑i=1⌊nd⌋μi∗f(id) 所以 F(n)=∑d=1ng(d)∗ϕd=∑d=1nϕd∑i=1⌊nd⌋μi∗f(id)

如此这般,套模版就好了。

代码

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long ll;

const int MAXN = 2e6 + 5;

int n, tot;
ll ans;
ll s[MAXN];
ll f[MAXN];
int pri[MAXN];
int phi[MAXN];
int miu[MAXN];
bool vis[MAXN];

void solve()
{
memset(vis, 0, sizeof(vis));
memset(phi, 0, sizeof(phi));
memset(miu, 0, sizeof(miu));
memset(s, 0, sizeof(s));
memset(f, 0, sizeof(f));
ans = tot = 0;
miu[1] = phi[1] = 1;

for (int i = 2; i <= n; i++)
{
if (!vis[i])
{
pri[tot++] =i ;
miu[i] = -1;
phi[i] = i - 1;
}
for (int j = 0, k; j < tot; j++)
{
k = i * pri[j];
if (k > n)
{
break;
}

vis[k] = 1;
if (i % pri[j] == 0)
{
miu[k] = 0;
phi[k] = phi[i] * pri[j];
break;
}

miu[k] = -miu[i];
phi[k] = phi[i] * (pri[j] - 1);
}
}

for (int i = 1; i <= n; i++)
{
s[phi[i]]++;
}
for (int i = 1; i <= n; i++)
{
for (int j = i; j <= n; j += i)
{
f[i] += s[j];
}
}
for (int i = 1; i <= n; i++)
{
f[i] = f[i] * f[i];
}
for (int i = 1; i <= n; i++)
{
if (miu[i] != 0)
{
for (int d = 1; i * d <= n; d++)
{
ans += miu[i] * phi[d] * f[i * d];
}
}
}
}

int main()
{
int T;
scanf("%d", &T);

while (T--)
{
scanf("%d", &n);

solve();

printf("%lld\n", ans);
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  默比乌斯反演