题目链接:https://codeforc.es/contest/900/problem/D
题目大意:要你构造一个长度为(未知)的数组,使得且,,输出种类数。
思路:从,我们可以推断出对于构造的数组,每个数都是的倍数,且所有数的和为,由此可以联想到类似于隔板法:将份至少分成两份,最多分成份,不能为空
这样总的分类数即为:令为份数,
但是我们注意到单纯这样分是存在问题的,例如:,我们可能会分出这样错误的情况,所以我们需要去除掉不合法的种类数,我们可以发现:不合法的种类数产生的原因为:份数为的因子,所以我们减掉份数为的因子的值就了。
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
ll qpow(ll x,ll y){
ll ans=1;
while(y){
if(y&1){
ans=ans*x%mod;
}
x=x*x%mod;
y>>=1;
}
return ans;
}
map<ll ,ll >mp;
ll dfs(ll x){
if(mp[x]){
return mp[x];//用map映射直接返回,减少多余计算
}
if(x==1){
return 1;
}
mp[x]=(qpow(2,x-1)-1+mod)%mod;
for(ll i=2;i*i<=x;i++){
if(x%i==0){
mp[x]=(mp[x]-dfs(x/i)+mod)%mod;
if(i*i!=x){
mp[x]=(mp[x]-dfs(i)+mod)%mod;
}
}
}
return mp[x];
}
int main()
{
ll x,y;
cin>>x>>y;
if(y%x!=0){//序列总和不是gcd的倍数
cout<<0<<endl;
}
else{
ll cnt=y/x;
ll ans=dfs(cnt);
cout<<ans<<endl;
}
return 0;
}