[CF547C] Mike and Foam

[CF547C] Mike and Foam - 组合,容斥,数论

Description

给一些数,每次操作将某个数激活或者禁用,输出当前所有激活的数中互质的数对的个数。数大小不超过 (5 imes 10^5)

Solution

一个数的不同的质因子最多有 7 个

显然求互质是不大方便的,我们考虑转化为非互质,即有公共的质因子

现在考虑一个数上架的情况,所有与他有公共质因子的数都会产生一次贡献

所以我们容斥着统计就可以了

具体地,我们需要维护一个 (cnt[i]) 表示当前有多少个激活的数以 i 为因子,计算时枚举每个因子是否选择,然后容斥统计答案即可

#include <bits/stdc++.h>
using namespace std;

#define int long long

const int N = 1000005;
int n, q, a[N], b[N], cnt[N], ans = 0, tot = 0;
vector<int> fac[N], allfac[N];

signed main()
{
    ios::sync_with_stdio(false);
    cin >> n >> q;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    for (int i = 1; i <= n; i++)
    {
        int t = a[i];
        for (int j = 2; j * j <= a[i]; j++)
        {
            if (t % j == 0)
            {
                while (t % j == 0)
                    t /= j;
                fac[i].push_back(j);
            }
        }
        if (t > 1)
            fac[i].push_back(t);
        }
    for (int i = 1; i <= q; i++)
    {
        int id;
        cin >> id;
        if (b[id] == 0)
        {
            b[id] = 1;
            int siz = fac[id].size();
            for (int s = 0; s < 1 << siz; s++)
            {
                int sign = __builtin_popcount(s) % 2 ? 1 : -1;
                int num = 1;
                for (int j = 0; j < siz; j++)
                    if (s & (1 << j))
                        num *= fac[id][j];
                ans += cnt[num] * sign;
            }
            for (int s = 1; s < 1 << siz; s++)
            {
                int num = 1;
                for (int j = 0; j < siz; j++)
                    if (s & (1 << j))
                        num *= fac[id][j];
                cnt[num]++;
            }
            ++tot;
        }
        else
        {
            b[id] = 0;
            int siz = fac[id].size();
            for (int s = 1; s < 1 << siz; s++)
            {
                int num = 1;
                for (int j = 0; j < siz; j++)
                    if (s & (1 << j))
                        num *= fac[id][j];
                cnt[num]--;
            }
            for (int s = 0; s < 1 << siz; s++)
            {
                int sign = __builtin_popcount(s) % 2 ? 1 : -1;
                int num = 1;
                for (int j = 0; j < siz; j++)
                    if (s & (1 << j))
                        num *= fac[id][j];
                ans -= cnt[num] * sign;
            }
            --tot;
        }
        cout << tot * (tot - 1) / 2 - ans << endl;
    }
}
原文地址:https://www.cnblogs.com/mollnn/p/14487326.html