CF 900D Unusual Sequences

题目链接
\(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\not = 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\n");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\n",(ans%mod+mod)%mod);
	return 0;
}
posted @ 2019-01-26 08:08  LeTri  阅读(223)  评论(0编辑  收藏  举报