编程语言:Java
题目链接:http://poj.org/problem?id=3046
题解:题目绕死我了,然后果断看题解,好家伙题解也看不懂,可能现在问我,我也还是一样搞不懂,解释都写在注解了,有错误希望及时指正,我菜我菜。
结果:AC
import java.io.*;
import java.util.*;
public class Main {
static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
static Scanner sc = new Scanner(new BufferedInputStream(System.in));
//滚动数组,不然空间大小就来到了1000*1000*100,可能会死的很难看
static int[][] dp = new int[2][100003];
//为每个家族的蚂蚁都计个数
static int[] num = new int[1003];
static int MOD = 1000000;
//强调一点:dp数组的含义:
// ①横坐标无含义;
// ②纵坐标是一组蚂蚁可能的长度,比如例题中可能的最长长度就是所有蚂蚁都在一个组中
// ③坐标的值表示能够构成小于等于该长度的不同蚂蚁组的个数,比如第三项的值就等于构成每组一个蚂蚁、每组两个蚂蚁、每组三个蚂蚁的组合总和
public static void main(String[] args) throws IOException {
int t = sc.nextInt();
int a = sc.nextInt();
int s = sc.nextInt();
int b = sc.nextInt();
for (int i = 0; i < a; i++) {
num[sc.nextInt() - 1]++;
}
//一个蚂蚁都不取,那自然是可以的,并且只有一种办法
dp[0][0] = 1;
dp[1][0] = 1;
for (int i = 0; i < t; i++) {
//此时考虑第i个家族的蚂蚁
for (int j = 1; j <= b; j++) {
if (j <= num[i]) {
//当需要组成的蚂蚁组别的长度小于num[i]的时候,表示前面任何一种蚂蚁组别,无论缺少了几只蚂蚁,第i个家族的蚂蚁都能够给你弥补上
//所以这里的递推公式如下:
// 1、第一项是前一项的值,表示前缀和;
// 2、第二项表示用i项组成长度为j的蚂蚁组别(其中包含了所有情况),也就是下面几项的和:
// (1)用前i-1个家族的蚂蚁组成长度为0的蚂蚁组别
// (2)用前i-1个家族的蚂蚁组成长度为1的蚂蚁组别
// ........
// (j+1)用前i-1个家族的蚂蚁组成长度为j的蚂蚁组别
dp[(i + 1) & 1][j] = (dp[(i + 1) & 1][j - 1] + dp[i & 1][j]) % MOD;
} else {
//当需要组成的蚂蚁组别的长度大于num[i]的时候,则第i个家族的蚂蚁最多就只能补上num[i],
// 所以这里的递推公式如下:
// 1、第一项是前一项的值,表示前缀和;
// 2、第二项表示用i项组成长度为j的蚂蚁组别(其中包含了所有情况),也就是下面几项的和:
// (1)用前i-1个家族的蚂蚁组成长度为j-num[i]的蚂蚁组别
// (2)用前i-1个家族的蚂蚁组成长度为j-num[i]+1的蚂蚁组别
// ........
// (num[i]+1)用前i-1个家族的蚂蚁组成长度为j的蚂蚁组别
dp[(i + 1) & 1][j] = (dp[(i + 1) & 1][j - 1] + dp[i & 1][j] - dp[i & 1][j - num[i] - 1] + MOD) % MOD;
}
}
}
int ans = 0;
for (int i = s; i <= b; i++) {
ans = (ans + dp[t & 1][i]) % MOD;
}
out.println(ans);
out.flush();
}
}