题目链接: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<bits/stdc++.h>
#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;
}