L i n k Link Link
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[i−1][j−k]
然而我打成了
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;
}