【DP】统计蚂蚁(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

说明

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


桶排,t[i]为第i种蚂蚁的数量。
设f[i][j]为前i种蚂蚁选j个
转移:
f [ i ] [ j ] = Σ k = 0 m i n ( j , t [ i ] ) f [ i − 1 ] [ j − k ] f[i][j] = \Sigma_{k=0}^{min(j,t[i])} f[i-1][j-k] f[i][j]=Σk=0min(j,t[i])f[i1][jk]
代码可以用滚动数组和前缀和优化,但是数据比较小就跑过了…


代码

#include
#include
#include
using namespace std;
const int mod = 1000000;
int t,a,s,b,ll,ans;
int k[5005],f[1005][5005],sum[1005][5005];
int main(){
 scanf("%d%d%d%d",&t,&a,&s,&b);
 for(int i = 1; i <= a; ++i){
  scanf("%d",&ll);
  ++k[ll];  
 }
 f[0][0] = 1;
 for(int i = 1; i <= t; ++i){
  for(int j = 0; j <= b; ++j){
   for(int kk = 0; kk <= min(j,k[i]); ++kk)
     f[i][j] = (f[i][j] + f[i-1][j-kk]) % mod; 
  }
 }
 for(int i = s; i <= b; ++i) ans = (ans + f[t][i]) % mod;
 printf("%d",ans);
}

你可能感兴趣的:(DP)