动态规划统计蚂蚁 (ants)

Posted konjaklaf

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态规划统计蚂蚁 (ants)相关的知识,希望对你有一定的参考价值。

题目

描述

蚂蚁山上有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只蚂蚁的方法总和。

输入

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

输出

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

样例输入

3 5 2 3
1
2
2
1
3

样例输出

10

大意

有 A 个 T 种物品,求取 (i in [S,B])共有多少种方法,答案取模 1000000

题解

首先用一个桶存储存每种蚂蚁的数量,设为 x[] 。

60分左右

动态规划,设 F[i][j] 为前 i 种物品选 j 个的方案数。则
(F_{0,0}=1)
(F_{i,j}=sum_{k=0}^{min{(j,x_i)}} F_{i-1,j-k})
但是这样的时间复杂度是 (O(Tsum x_i)) ,会超时。

满分

上面的 F[i][] 都是从 F[i-1][] 得来的,因此我们想到了前缀和
设 S[i][j] 表示前 i 种物品取 0~i 个时的方案总和
前缀和我们并不陌生, (S_{i,j}=S_{i,j-1}+F_{i,j})
那怎么求 F[i][j] 呢?
60 分做法时的公式得知,F[i][j] 等于 F[i-1][j-k] 到 F[i-1][j] 的和
这一段和就是 (S_{i-1,j}-S_{i-1,j-k-1}) ,也就是 (S_{i-1,j}-S_{i-1,j-min(x[i],j)-1})
最后注意初始化
(S[2 extit{~}A][0]=1)
(S[0][0 extit{~}T]=min{(x[1],0 extit{~}T)+1})
就可以通过了

标程

#include<bits/stdc++.h>
#define rg register int
using namespace std;
const int mod=1000000;
int n,m,l,r,t,x[5005],f[1005][5005],s[1005][5005],ans;
int main(){
	freopen("ants.in","r",stdin);
	freopen("ants.out","w",stdout);
	scanf("%d%d%d%d",&n,&m,&l,&r);
	for(rg i=1;i<=m;i++) scanf("%d",&t),++x[t];
	for(rg i=0;i<=m;i++) s[1][i]=min(i,x[1])+1;
	for(rg i=2;i<=n;i++){
		s[i][0]=1;
		for(rg j=1;j<=m;j++){
			f[i][j]=(s[i-1][j]-s[i-1][j-min(x[i],j)-1])%mod;
			s[i][j]=(s[i][j-1]+f[i][j])%mod;
		}
	}
	for(rg i=l;i<=r;i++) ans=(ans+f[n][i])%mod;
	printf("%d",ans);
}




















以上是关于动态规划统计蚂蚁 (ants)的主要内容,如果未能解决你的问题,请参考以下文章

ZOJ-3279 Ants 树状数组 + 二分

Ant(蚂蚁搬家)

Ant(蚂蚁搬家)

bzoj 3111 蚂蚁 动态规划

POJ1852 Ants

蚂蚁电竞ant27vu菜单打不开