码迷,mamicode.com
首页 > 其他好文 > 详细

【动态规划】统计蚂蚁 (ants)

时间:2020-07-17 22:24:26      阅读:121      评论:0      收藏:0      [点我收藏+]

标签:names   空格   公式   ons   初始   规划   name   和我   复杂   

题目

描述

蚂蚁山上有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(T\sum 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\textit{~}A][0]=1\)
\(S[0][0\textit{~}T]=\min{(x[1],0\textit{~}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)

标签:names   空格   公式   ons   初始   规划   name   和我   复杂   

原文地址:https://www.cnblogs.com/KonjakLAF/p/13330090.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!