【51nod】猴猴吃香蕉【背包】

题目大意:

题目链接:http://www.51nod.com/Contest/Problem.html#contestProblemId=1149

猴猴最爱吃香蕉了。每天猴猴出门都会摘很多很多的香蕉,每个香蕉都有一个甜度,猴猴不一定要把所有的香蕉都吃掉,猴猴每天都有一个心情值K,猴猴希望当天吃的香蕉满足这么一个条件,这些香蕉的甜度乘积恰好等于K,但是猴猴并不知道有多少种方法,于是猴猴把这个问题交给你。


思路:

m ≤ 1 0 8 m\leq 10^8 m108,根据试除法的推论, m m m的约束不会超过 2 m = 2 × 1 0 4 2\sqrt{m}=2\times 10^4 2m =2×104个。
所以我们求出 m m m的所有因数并排序,然后设 f [ i ] f[i] f[i]表示第组成第 i i i个因数的方案数,那么我们对于读入的 x x x,枚举 m m m的所有因数 v v v,如果 x x x v v v的因数,那么就有
f [ p o s [ v ] ] = f [ p o s [ v ] ] + f [ p o s [ v x ] ] f[pos[v]]=f[pos[v]]+f[pos[\frac{v}{x}]] f[pos[v]]=f[pos[v]]+f[pos[xv]]
其中 p o s [ x ] pos[x] pos[x]表示 x x x m m m的第几个因数。
最终答案是 f [ k ] f[k] f[k]
注意 m m m的因数要从大到小排序,因为01背包是会覆盖原来顺序的。


代码:

#include <map>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int N=20010,MOD=1000000007;
int T,n,m,x,k,f[N],v[N];
map<int,int> pos;

int main()
{
	scanf("%d",&T);
	while (T--)
	{
		memset(f,0,sizeof(f));
		memset(v,0,sizeof(v));
		k=0; pos.clear();
		scanf("%d%d",&n,&m);
		for (int i=1;i*i<=m;i++)
			if (!(m%i))
			{
				v[++k]=i;
				if (i*i!=m) v[++k]=m/i;
			}
		sort(v+1,v+1+k);
		for (int i=1;i<=k;i++) pos[v[i]]=i;
		f[1]=1;
		for (int i=1;i<=n;i++)
		{
			scanf("%d",&x);
			if(m%x!=0) continue;
			for (int j=k;j>=1;j--)
				if (!(v[j]%x)) f[j]=(f[j]+f[pos[v[j]/x]])%MOD;
		}
		printf("%d\n",f[pos[m]]);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值