題目連接
\(Description\)
給定\(x,y\),求有多少個數列知足\(gcd(a_i)=x且\sum a_i=y\)。答案對\(10^9+7\)取模。spa
\(1≤x,y≤10^9\)code
\(Solution\)
\(y\)若是不是\(x\)的倍數,答案爲\(0\)ip
而後呢get
令\(y/=x\),問題就變成了求有多少個數列知足\(gcd(a_i)=1且\sum ai=y'\)io
若是沒有\(gcd\)爲\(1\)的限制?
隔板法可得\(ans=\sum_{i=0}^{y-1}C_{y-1}^i=2^{y-1}\)class
令\(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)\]
而後就能夠從前日後遞推了。gc
複雜度\(O(d(y/x)^2)\),其中\(d(x)\)爲\(x\)的約數個數。di
固然\[g(i)=\sum_{d|i}f(d)\]
就是通常的莫比烏斯反演的形式。
能夠直接得出
\[f(i)=\sum_{d|i}\mu(d)g(\frac{i}{d})\]while
#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; }