Loading

1436F - Sum Over Subsets 莫比乌斯反演相关

传送门

解题思路

\(g(n)\)为集合\(gcd\)恰好为\(n\)时的答案

不太好算

考虑再设一个\(f(n)\)为集合\(gcd\)\(n\)的倍数的方案数

\(f(n)=\sum\limits_{n|d}g(d)\)

这是显然的莫比乌斯反演形式

那么\(g(n)=\sum\limits_{n|d}\mu(\frac{d}{n})f(d)\)

那么这题答案相当于\(g(1)=\sum\limits_{n|d}\mu(d)f(d)\)

也就是要处理出所有的\(f(i)\)

对于一个\(i\),我们取出所有为\(i\)的倍数的数,那么这些数的贡献就是\(f(i)\)

对于\(\sum_{x \in A}{x} \cdot \sum_{y \in B}{y}\)枚举每对\(xy\)的贡献

\(|S|\)为当前集合A的大小

当x和y是同一个数的时候,贡献是\(x^2(|S|-1)2^{|S|-2}freq[x]\)

当x和y相等的时候,贡献是\(x^2[(|S|-2)2^{|S|-3}+2^{|S|-2}]freq[x](freq[x]-1)\)

当x不等于y的时候,贡献是\(xy[(|S|-2)2^{|S|-3}+2^{|S|-2}]freq[x]freq[y]\)

复杂度就是调和级数里面带个快速幂,大概是\(nlog^2\)

代码

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/trie_policy.hpp>
using namespace __gnu_pbds;
using namespace std;
// freopen("k.in", "r", stdin);
// freopen("k.out", "w", stdout);
// clock_t c1 = clock();
// std::cerr << "Time:" << clock() - c1 <<"ms" << std::endl;
//#pragma comment(linker, "/STACK:1024000000,1024000000")
mt19937 rnd(time(NULL));
#define de(a) cout << #a << " = " << a << endl
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, a, n) for (int i = n; i >= a; i--)
#define ls ((x) << 1)
#define rs ((x) << 1 | 1)
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef pair<char, char> PCC;
typedef pair<ll, ll> PLL;
typedef vector<int> VI;
#define inf 0x3f3f3f3f
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll MAXN = 1e6 + 7;
const ll MAXM = 4e5 + 7;
const int MOD = 998244353;
const double eps = 1e-7;
int mu[MAXN], pri[MAXN], vis[MAXN], tot = 0;
void init()
{
    mu[1] = 1;
    for (int i = 2; i < MAXN; i++)
    {
        if (!vis[i])
            pri[++tot] = i, mu[i] = -1;
        for (int j = 1; j <= tot && pri[j] * i < MAXN; j++)
        {
            vis[i * pri[j]] = 1;
            if (i % pri[j] == 0)
            {
                mu[i * pri[j]] = 0;
                break;
            }
            else
                mu[i * pri[j]] = -mu[i];
        }
    }
}
ll qpw(ll a, ll b)
{
    ll ans = 1;
    while (b)
    {
        if (b & 1)
            ans = (1LL * ans * a) % MOD;
        a = (1LL * a * a) % MOD;
        b >>= 1;
    }
    return ans;
}
int num[MAXN];
ll f[MAXN];
vector<PII> vec;
int main()
{
    ll inv = qpw(2, MOD - 2);
    int n;
    init();
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
    {
        int x, y;
        scanf("%d%d", &x, &y);
        num[x] += y;
    }
    for (int i = 1; i <= 100000; i++)
    {
        vec.clear();
        ll cnt = 0;
        ll tmp = 0;
        for (int j = i; j <= 100000; j += i)
            if (num[j])
                vec.emplace_back(j, num[j]), cnt += num[j], (tmp += 1LL * j * num[j]) %= MOD;
        for (auto j : vec)
        {
            ll tt = 0;
            if (cnt >= 2)
            {
                tt = qpw(2, cnt - 2);
                (f[i] += 1LL * (cnt - 1) % MOD * j.first % MOD * j.first % MOD * tt % MOD * j.second % MOD) %= MOD;
            }
            if (cnt >= 3)
                (tt += 1LL * (cnt - 2) % MOD * tt % MOD * inv % MOD) %= MOD;
            (f[i] += 1LL * j.first * j.first % MOD * tt % MOD * j.second % MOD * (j.second - 1) % MOD);
            (f[i] += 1LL * j.first * j.second % MOD * tt % MOD * (tmp - 1LL * j.first * j.second % MOD) % MOD) %= MOD;
        }
    }
    ll ans = 0;
    for (int i = 1; i <= 100000; i++)
        (ans += 1LL * mu[i] * f[i] % MOD) %= MOD;
    printf("%lld\n", (ans % MOD + MOD) % MOD);
    return 0;
}
posted @ 2020-10-30 22:03  GrayKido  阅读(257)  评论(0编辑  收藏  举报