题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6578
计数问题想到dp不过分吧...
dp[i][j][k][w]为第1-i位置中4个数最后一次出现的位置从大到小排列后为i>=j>=k>=w,但是会MLE,所以把i滚动掉。
但是这里有限制条件,把所有限制条件按右端点用vector存一下,然后处理到第i个位置时,枚举每个状态和限制条件,如果当前状态不满足则归0。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include <algorithm> 2 #include<iostream> 3 #include <cstdio> 4 #include <vector> 5 #include <cstring> 6 using namespace std; 7 typedef long long ll; 8 const int maxn = 100 + 5; 9 const int mod = 998244353; 10 int n, m, ans; 11 int dp[2][maxn][maxn][maxn]; 12 vector <pair<int, int>> a[maxn]; 13 int main() { 14 int pos; 15 cin >> pos; 16 while (pos--) { 17 int ans = 0; 18 scanf("%d %d", &n, &m); 19 for (int i = 1; i <= n; i++) 20 a[i].clear(); 21 for (int i = 0; i < m; i++) { 22 int l, r, x; 23 scanf("%d%d%d", &l, &r, &x); 24 a[r].push_back(pair<int, int>(l, x)); 25 } 26 dp[0][0][0][0] = 1; 27 int now = 1; 28 for (int i = 1; i <= n; i++, now ^= 1) { 29 for (int j = 0; j <= i; j++) 30 for (int k = 0; k <= j; k++) 31 for (int t = 0; t <= k; t++) 32 dp[now][j][k][t] = 0; 33 for (int j = 0; j < i; j++) 34 for (int k = 0; k <= j; k++) 35 for (int t = 0; t <= k; t++) { 36 dp[now][j][k][t] = (dp[now ^ 1][j][k][t] + dp[now][j][k][t]) % mod; 37 dp[now][i - 1][k][t] = (dp[now ^ 1][j][k][t] + dp[now][i - 1][k][t]) % mod; 38 dp[now][i - 1][j][t] = (dp[now ^ 1][j][k][t] + dp[now][i - 1][j][t]) % mod; 39 dp[now][i - 1][j][k] = (dp[now ^ 1][j][k][t] + dp[now][i - 1][j][k]) % mod; 40 } 41 for (int j = 0; j < i; j++) 42 for (int k = 0; k <= j; k++) 43 for (int t = 0; t <= k; t++) 44 for (auto tmp : a[i]) 45 if (1 + (j >= tmp.first) + (k >= tmp.first) + (t >= tmp.first) != tmp.second) 46 dp[now][j][k][t] = 0; 47 } 48 now = n & 1; 49 for (int i = 0; i < n; i++) 50 for (int j = 0; j <= i; j++) 51 for (int k = 0; k <= j; k++) 52 ans = (ans + dp[now][i][j][k]) % mod; 53 printf("%d\n", ans); 54 } 55 56 }