动态规划统计蚂蚁 (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)的主要内容,如果未能解决你的问题,请参考以下文章