codeforces 900d Unusual Sequences

        题意:要求任意长度的数组,使得其和为x,每个元素gcd=y,求这样数组的数量。

        首先,由于每个元素可表示为x[i]*y,所以如果x%y!=0,那么这样的情况是不合法。

        所以我们可以将问题转化为求数组元素和为x/y,gcd=1的数组数量。

        由插板法可以得到和为x的数字共有2的x-1次方-1个情况。

        接着我们可以容斥,减去其含有的每一个因数出现的次数,由于原数的因数的因数还是原数的因数,所以记忆化搜索+递归实现即可。

         下附AC代码。

#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
map dp;
ll n,m;
ll quickpow(ll p,ll k)
{
	ll ans=1;
	while(k)
	{
		if(k&1)
		{
			ans=ans*p;ans%=mod;
		}
		p=p*p;p%=mod;
		k>>=1;
	}
	return ans;
}
ll dfs(ll now)
{
	if(now==1) return 1;
	if(dp[now]!=0) return dp[now];
	dp[now]=quickpow(2,now-1)-1;
	for(ll i=2;i*i<=now;i++)
	{
		if(now%i==0)
		{
			dp[now]-=dfs(i);
			if(i*i!=now)
				dp[now]-=dfs(now/i);
			dp[now]=(dp[now]%mod+mod)%mod;
		}
	}
	return dp[now];
}
int main()
{
	scanf("%I64d%I64d",&m,&n);
	if(n%m)
	{
		printf("0\n");
		return 0;
	}
	ll need=n/m;
	printf("%I64d\n",dfs(need));
}


你可能感兴趣的:(数位dp,容斥原理)