【DP】ssl 1508.统计蚂蚁(ants)

L i n k Link Link

s s l   1508 ssl\ 1508 ssl 1508

D e s c r i p t i o n Description Description

蚂蚁山上有T(1<=T<=1,000)种蚂蚁,标记为1…T,每种蚂蚁有N_i只蚂蚁(1<=N_i<=100),现有A(A<=5000)只蚂蚁,从中选出S,S+1,…,B(1<=S<=B<=A)只蚂蚁一共有多少种选法?
如有5只蚂蚁分别为{1,1,2,2,3},一共有3种蚂蚁,每一种蚂蚁的数量分别为2,2,1,以下是选不同数量蚂蚁的方法:

1个蚂蚁3种选法:{1}{2}{3}

2个蚂蚁5种选法:{1,1}{1,2}{1,3}{2,2}{2,3}

3个蚂蚁5种选法:{1,1,2}{1,1,3}{1,2,2}{1,2,3}{2,2,3}

4个蚂蚁3种选法:{1,2,2,3}{1,1,2,2}{1,1,2,3}

5个蚂蚁1种选法:{1,1,2,2,3}

你的任务是从中选S…B只蚂蚁的方法总和。

I n p u t Input Input

第一行: 4个空格隔开的整数: T, A, S和B;
第2到A+1行:每行一个整数表示蚂蚁的种类。

O u t p u t Output Output

输出从A只蚂蚁中选出S…B只蚂蚁的方法数,答案保留后6位。

S a m p l e Sample Sample I n p u t Input Input

3 5 2 3
1	
2
2
1
3

S a m p l e Sample Sample O u t p u t Output Output

10

H i n t Hint Hint

对于30%的数据:T<=30,A<=100;
对于50%的数据:T<=100,A<=400;
对于100%的数据:T<=1000,A<=5000;

S o l u t i o n Solution Solution

DP
f [ i ] [ j ] f[i][j] f[i][j]为前i种,总共选了j只蚂蚁的方案数
再枚举一个k,表示当前这种蚂蚁选了k只
那么动态转移方程就是 f [ i ] [ j ] = ∑ f [ i − 1 ] [ j − k ] f[i][j] = \sum f[i-1][j-k] f[i][j]=f[i1][jk]
然而我打成了 f [ i ] [ j + k ] f[i][j+k] f[i][j+k]然后再拿f[i][j]转移。。。不过问题不大
然后那个只输出后六位%一下就好了
某巨佬说什么优化都不大就A了???
我还打了快读和滚动数组

C o d e Code Code

#include<iostream>
#include<cstring>
#include<cstdio>
#define ll long long

using namespace std;

const int mo = 1000000;
ll T, A, S, B, X, ans;
ll num[5005], f[2][5005];

int read() 
{
	int x = 0, flag = 1; char ch = getchar();
	while (ch < '0' || ch > '9') {if (ch == '-') flag = -1; ch = getchar();}
	while (ch >= '0' && ch <= '9'){x = x * 10 + ch - '0'; ch = getchar();}
	return x * flag;
}//快读

int main()
{
	T = read(); A = read(); 
	S = read(); B = read();
	for (int i = 1; i <= A; ++i) { 
		X = read();
		num[X]++; 
		
	} 
	f[0 & 1][0] = 1;
	for (int i = 1; i <= T; ++i) {
		memset(f[i & 1], 0, sizeof(f[i & 1]));
		for (int j = 0; j <= B; ++j)
			for (int k = 0; k <= num[i] && k + j <= B; ++k)
				f[i & 1][j + k] = f[i & 1][j + k] + f[(i - 1) & 1][j] % mo;
	}
	for (int ll i = S; i <= B; ++i)
		ans = (ans + f[T & 1][i]) % mo;
	printf("%lld", ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值