题意:
给定x,y,问有多少种序列a,
满足a[i]>=1,gcd(a[])=x,且sum(a[])=y.
数据范围:x,y<=1e9
解法:
y % x ! = 0 时 肯 定 无 解 问 题 可 以 转 换 为 满 足 和 为 k = y / x , g c d = 1 的 序 列 数 量 设 g ( k ) 为 满 足 和 为 k 的 方 案 数 因 为 序 列 的 长 度 可 以 不 定 , 可 以 看 作 是 k 个 1 , 在 k − 1 个 空 位 插 入 0 到 k − 1 个 隔 板 因 此 g ( k ) = ∑ i = 0 k − 1 C ( k − 1 , i ) = 2 k − 1 g ( k ) 没 有 考 虑 g c d , 里 面 包 含 g c d = 1 到 g c d = k 的 所 有 方 案 . 设 f ( x ) 为 g c d = 1 , 和 为 y / x 的 方 案 数 , 因 为 对 于 g ( k ) , 所 有 可 能 的 序 列 的 g c d 一 定 是 k 的 约 数 因 此 g ( k ) = ∑ d ∣ k f ( k d ) . 为 什 么 是 f ( k d ) 呢 ? f ( k d ) 的 和 是 k d 不 是 k 呀 ? 这 是 因 为 和 为 k d , g c d = 1 的 序 列 , 每 个 数 都 乘 上 d 之 后 就 变 成 和 为 k , g c d = d 的 序 列 了 反 演 得 : f ( k ) = ∑ d ∣ k μ ( d ) g ( k d ) O ( s q ( k ) ) 枚 举 因 子 d 即 可 . 预 处 理 质 数 , 然 后 μ ( d ) 就 可 以 O ( s q ( d ) / l o g ( d ) ) 计 算 . y\%x!=0时肯定无解\\ 问题可以转换为满足和为k=y/x,gcd=1的序列数量\\ 设g(k)为满足和为k的方案数\\ 因为序列的长度可以不定,可以看作是k个1,在k-1个空位插入0到k-1个隔板\\ 因此g(k)=\sum_{i=0}^{k-1}C(k-1,i)=2^{k-1}\\ g(k)没有考虑gcd,里面包含gcd=1到gcd=k的所有方案.\\ 设f(x)为gcd=1,和为y/x的方案数,\\ 因为对于g(k),所有可能的序列的gcd一定是k的约数\\ 因此g(k)=\sum_{d|k}f(\frac{k}{d}).\\ 为什么是f(\frac{k}{d})呢?f(\frac{k}{d})的和是\frac{k}{d}不是k呀?\\ 这是因为和为\frac{k}{d},gcd=1的序列,每个数都乘上d之后\\ 就变成和为k,gcd=d的序列了\\ 反演得:f(k)=\sum_{d|k}\mu(d)g(\frac{k}{d})\\ O(sq(k))枚举因子d即可.\\ 预处理质数,然后\mu(d)就可以O(sq(d)/log(d))计算. y%x!=0时肯定无解问题可以转换为满足和为k=y/x,gcd=1的序列数量设g(k)为满足和为k的方案数因为序列的长度可以不定,可以看作是k个1,在k−1个空位插入0到k−1个隔板因此g(k)=i=0∑k−1C(k−1,i)=2k−1g(k)没有考虑gcd,里面包含gcd=1到gcd=k的所有方案.设f(x)为gcd=1,和为y/x的方案数,因为对于g(k),所有可能的序列的gcd一定是k的约数因此g(k)=d∣k∑f(dk).为什么是f(dk)呢?f(dk)的和是dk不是k呀?这是因为和为dk,gcd=1的序列,每个数都乘上d之后就变成和为k,gcd=d的序列了反演得:f(k)=d∣k∑μ(d)g(dk)O(sq(k))枚举因子d即可.预处理质数,然后μ(d)就可以O(sq(d)/log(d))计算.
code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=1e6+5;
const int mod=1e9+7;
int notprime[maxm];
int prime[maxm],cnt;
int x,y;
int ppow(int a,int b,int mod){
int ans=1%mod;a%=mod;
while(b){
if(b&1)ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
int mu(int x){
if(x==1)return 1;
int ans=1;
for(int j=0;j<cnt&&prime[j]*prime[j]<=x;j++){
if(x%prime[j]==0){
int cnt=0;
while(x%prime[j]==0){
x/=prime[j];
cnt++;
}
if(cnt!=1)return 0;
ans=-ans;
}
}
if(x!=1)ans=-ans;
return ans;
}
int g(int x){
return ppow(2,x-1,mod);
}
void init(){
for(int i=2;i<maxm;i++){
if(!notprime[i]){
prime[cnt++]=i;
}
for(int j=0;j<cnt;j++){
if(prime[j]*i>=maxm)break;
notprime[prime[j]*i]=1;//素数的倍数标记为非素数
if(i%prime[j]==0)break;//看外面解释
}
}
}
signed main(){
init();
cin>>x>>y;
if(y%x!=0){
cout<<0<<endl;
return 0;
}
int k=y/x;
int ans=0;
for(int i=1;i*i<=k;i++){
if(k%i==0){
ans+=mu(i)*g(k/i);
if(k/i!=i){
ans+=mu(k/i)*g(i);
}
ans%=mod;
}
}
ans=(ans%mod+mod)%mod;
cout<<ans<<endl;
return 0;
}