Codeforces 900D Unusual Sequences

题目链接:https://codeforces.com/problemset/problem/900/D

题目:给定 x, y (1 <= x, y <= 1e9)  问有多少个序列满足   a1+a2+......+an = y  且 gcd(a1, a2, a3......, an) = x.  (ai > 0)

思路: 显然当 y%x != 0 时无解。然后问题就等价于将有多少个序列满足a1+a2+....+an = y/x 且 gcd = 1. 因为将n个东西分成任意多份,每一份都不能为空的分法有2^(t-1)种. (隔板法). 但此时不能保证gcd = 1.  但是我们可以枚举他的gcd(y/x 的因子)  再减去这些不符合的. 设f(p)代表gcd为p的倍数的方案个数则 f(p) = 2^((y/x)/p - 1),然后就可以容斥了.

代码:

#include
#define ll long long
using namespace std;
const int maxn = 3e4+5e3;
const ll mod = 1e9+7;

ll prime[maxn];
bool vis[maxn];
int cnt = 0;

void Prime() {
    memset(vis, false, sizeof vis);
    for(int i = 2; i < maxn; i++) {
        if(!vis[i])  prime[cnt++] = i*1ll;
        for(int j = 0; j < cnt && i*prime[j] < maxn; j++) {
            vis[i*prime[j]] = true;
            if(i % prime[j] == 0)  break;
        }
    }
}

int Mo(ll k) {
    if(k == 1)  return 1;
    int ans = 1;
    for(int i = 0; i < cnt && prime[i]*prime[i] <= k; i++) {
        int num = 0;
        while(k % prime[i] == 0) {
            k /= prime[i];
            num++;
        }
        if(num > 1)  return 0;
        if(num == 1)  ans *= -1;
    }
    if(k != 1)  return -ans;
}

ll pow_mod(ll p, ll k) {
    ll ans = 1;
    while(k) {
        if(k & 1)  ans = ans*p%mod;
        p = p*p%mod;  k >>= 1;
    }
    return ans;
}

int main() {
    Prime();
    ll x, y;
    scanf("%lld%lld", &x, &y);
    if(y % x != 0)  {
        printf("0\n");
        return 0;
    }
    y /= x;
    ll ans = 0;
    for(ll i = 1; i*i <= y; i++) {
        if(y % i == 0) {
            ans = ((ans+Mo(y/i)*pow_mod(2, i-1))%mod+mod)%mod;
            if(i*i != y)  ans = ((ans+Mo(i)*pow_mod(2, y/i-1))%mod+mod)%mod;
        }
    }
    printf("%lld\n", ans);
    return 0;
}

 

你可能感兴趣的:(Codeforces,Math)