POJ 3046---Ant Counting(多重组合数)

                                                        POJ 3046---Ant Counting

                http://poj.org/problem?id=3046

多重组合数问题原型:

有n种物品,第i种物品有a[i]个。不同种类可以取分但相同种类物品无法区分,从这些物品中取出m个的话,有多少种取法。

题意理解:

有T种蚂蚁,问这些蚂蚁分别取出 S.S+1...B 个的话,有多少种取法,就是原型中有若干个不同的m。


dp[i][j]:从前i种物品中取出j个的组合总种类数。

递推关系:从前i-1种取出j-k个,第i种取出k个。

dp[i][j]=∑dp[i-1][j-k](k从0到min(j,a[i])

一般这种连加符号或者max(完全背包不就是?)都根据递推定义,分离一项进行化简。

①:当j<=a[i]

dp[i][j]=∑dp[i-1][j-k](k从0到j:j,j-1...1,0)

        =dp[i-1][j]+∑dp[i-1][j-k](k从1到j:j-1..0)

        =dp[i-1][j]+∑dp[i-1][j-1-(k-1)]

        =dp[i-1][j]+dp[i][j-1]

②:a[i]<j

dp[i][j]=∑dp[i-1][j-k](k从0到a[i]j,j-1...j-a[i])

=dp[i-1][j]+∑dp[i-1][j-k](k从1到a[i]:j-1...j-a[i])

=dp[i-1][j]+∑dp[i-1][j-1-(k-1)]  dp[i][j-1],先+再-)

=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1-a[i]]


初始化:dp[i][0]=1(一个都不取的方法总是只有1种)


注意:不能用一维数组,原因:当前位置的状态取决于上,左上,和左。左上要序,左要序,矛盾!所以只能滚动数组了。


AC代码

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define M (int)1e6
int dp[2][100*1000+5];
int ant[1005];

int main()
{
	int T, A, S, B;
	cin >> T >> A >> S >> B;
	for (int i = 1; i <= A; i++)
	{   int x; scanf("%d", &x);
		ant[x]++;	
	}
	dp[0][0] = dp[1][0] = 1;
	for (int i = 1; i <= T; i++)
		for (int j = 1; j <= B; j++)
		{
			if (j >ant[i])
				dp[i % 2][j] = (dp[i % 2][j - 1] + dp[(i-1) % 2][j] - dp[(i-1) % 2][j - 1 - ant[i]] + M) % M;
			else dp[i % 2][j] = (dp[i % 2][j - 1] + dp[(i - 1) % 2][j]) % M;
		}
	int ans=0;
	for (int i = S; i <= B; i++)
		ans = (ans + dp[T % 2][i]) % M;

	cout << ans<<endl;
	system("pause");

}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值