[CF900D] Unusual Sequences - 组合,容斥,dp

Description

输入x,y,求有多少个数列满足其gcd为x,和为y。

Solution

令 m=y/x,则答案等于 gcd=1,sum=m 的数列个数

\(f[i]\) 表示 sum=i 的数列个数

\(g[i]\) 表示 sum|i 的数列个数

\(g[i]=\sum_{d|i} f[d]\)

\(g[i]\) 是容易求出的,根据隔板法,\(g[i]=2^{i-1}\)

\(f[i]\) 有两种方法,一种是手动容斥,一种是莫比乌斯反演

这里我们用手动容斥,枚举 gcd=d,然后删去 f(n/d)

\(f[i] = g[i] - \sum_{d|i, d<i} f[i/d]\)

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

#define int long long

const int mod = 1e9 + 7;

namespace math_mod
{
    int c__[5005][5005], fac__[3000005];

    int qpow(int p, int q)
    {
        return (q & 1 ? p : 1) * (q ? qpow(p * p % mod, q / 2) : 1) % mod;
    }

    int inv(int p)
    {
        return qpow(p, mod - 2);
    }

    int fac(int p)
    {
        if (p <= 3000000)
            return fac__[p];
        if (p == 0)
            return 1;
        return p * fac(p - 1) % mod;
    }

    int __fac(int p)
    {
        return fac(p);
    }

    int ncr(int n, int r)
    {
        if (r < 0 || r > n)
            return 0;
        return fac(n) * inv(fac(r)) % mod * inv(fac(n - r)) % mod;
    }

    void math_presolve()
    {
        fac__[0] = 1;
        for (int i = 1; i <= 3000000; i++)
        {
            fac__[i] = fac__[i - 1] * i % mod;
        }
        for (int i = 0; i <= 5000; i++)
        {
            c__[i][0] = c__[i][i] = 1;
            for (int j = 1; j < i; j++)
                c__[i][j] = c__[i - 1][j] + c__[i - 1][j - 1], c__[i][j] %= mod;
        }
    }

    int __c(int n, int r)
    {
        if (r < 0 || r > n)
            return 0;
        if (n > 5000)
            return ncr(n, r);
        return c__[n][r];
    }
}

using namespace math_mod;
int m;
map<int, int> f;

int solve(int x)
{
    if (f.find(x) != f.end())   
        return f[x];
    int ans = qpow(2, x - 1);
    vector<int> fac;
    for (int i = 2; i * i <= x; i++)
        if (x % i == 0)
        {
            fac.push_back(i);
            if (i * i != x)
                fac.push_back(x / i);
        }
    fac.push_back(1);
    for (auto i : fac)
        ans = (ans - solve(i) + mod) % mod;
    return f[x] = ans;
}

signed main()
{
    ios::sync_with_stdio(false);
    int x, y;
    cin >> x >> y;
    m = y / x;
    f[1] = 1;
    if (y % x)
        cout << 0 << endl;
    else
        cout << solve(m) << endl;
}

相关文章: