题目链接
(Description)
给定(x,y),求有多少个数列满足(gcd(a_i)=x且sum a_i=y)。答案对(10^9+7)取模。
(1≤x,y≤10^9)
(Solution)
(y)如果不是(x)的倍数,答案为(0)
然后呢
令(y/=x),问题就变成了求有多少个数列满足(gcd(a_i)=1且sum ai=y')
如果没有(gcd)为(1)的限制?
隔板法可得(ans=sum_{i=0}^{y-1}C_{y-1}^i=2^{y-1})
令(f(i))表示(gcd(a_i)=1)且和为(i)的方案数,(g(i))表示和为(i)的方案数。
可得
[g(i)=2^i-1,g(i)=sum_{d|i}f(d)
]
要求的是(f(i)),所以把(f(i))的一项单独拿出来
[f(i)=g(i)-sum_{d|i,d
ot = i}f(d)
]
然后就可以从前往后递推了。
复杂度(O(d(y/x)^2)),其中(d(x))为(x)的约数个数。
当然$$g(i)=sum_{d|i}f(d)$$
就是一般的莫比乌斯反演的形式。
可以直接得出
[f(i)=sum_{d|i}mu(d)g(frac{i}{d})
]
#include<complex>
#include<cstdio>
using namespace std;
const int mod=1e9+7;
const int N=1e5+7;
int x,y,tot;
int d[N];
int qread()
{
int x=0;
char ch=getchar();
while(ch<'0' || ch>'9')ch=getchar();
while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x;
}
int GetMu(int x)
{
if(x==1)return 1;
int t=0,sqr=sqrt(x);
for(int i=2;i<=sqr;i++)
if(x%i==0)
{
t++;x/=i;
if(x%i==0)return 0;
}
if(x>1)t++;
return t&1?-1:1;
}
int Fpow(long long b,int p)
{
long long res=1;
for(;p;p>>=1,b=b*b%mod)
if(p&1)res=res*b%mod;
return res;
}
int main()
{
scanf("%d%d",&x,&y);
if(y%x){printf("0
");return 0;}
y/=x;
for(int i=1;i*i<=y;i++)
if(y%i==0)
{
d[++tot]=i;
if(i*i!=y)d[++tot]=y/i;
}
long long ans=0;
for(int i=1;i<=tot;i++)
ans+=GetMu(y/d[i])*Fpow(2,d[i]-1);
printf("%d
",(ans%mod+mod)%mod);
return 0;
}