codeforces 900d Unusual Sequences

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

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

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

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

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

         下附AC代码。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<map>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
map<ll,ll> 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));
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值