2019 multi

链接:http://acm.hdu.edu.cn/showproblem.php?pid=6578
思路:dp[a][b][c][d]表示0123四个数字最后结束的位置在abcd,因为四个数字无差别,我们可以把abcd的所有排列看成一种情况,换句话说,我们强制a < b < c < d,这样就复杂度可以 / 24。考虑我们要枚举当前位置,所有d转移后的地方一定是i,所以这一维可以滚掉,用abc以及i - 1四个位置信息来判断所有以r为右端点的限制,如果都满足就可以转移,否则就不能转移。注意这个题实在有点卡时间,所以要注意写法。。。。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73

using namespace std;

const int maxn = 105;
int dp[2][maxn][maxn][maxn];
const int mod = 998244353;
int T, n, m;

inline void (int &x, int y){
x += y;
if(x >= mod) x -= mod;
}

typedef pair<int, int> pii;
vector<pii> r[maxn];

inline bool check(int a, int b, int c, int d, int pos){
for(int i = 0; i < r[pos].size(); i++){
int s = 0;
if(r[pos][i].first <= a) s++;
if(r[pos][i].first <= b) s++;
if(r[pos][i].first <= c) s++;
if(r[pos][i].first <= d) s++;
if(s != r[pos][i].second) return false;
}
return true;
}

int main(){

ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> T;
while(T--){
cin >> n >> m;
memset(dp, 0, sizeof(dp));
int o = 0;
dp[0][0][0][0] = 1;
for(int i = 0; i <= n; i++) r[i].clear();
for(int i = 1; i <= m; i++){
int pl, pr, x;
cin >> pl >> pr >> x;
r[pr].push_back(pii(pl, x));
}
for(int i = 0; i < n; i++){
for(int j = i; j >= 0; j--){
for(int k = j; k >= 0; k--){
for(int p = k; p >= 0; p--) {
if(check(i, j, k, i + 1, i + 1))
add(dp[o ^ 1][i][j][k], dp[o][j][k][p]);
if(check(i, j, p, i + 1, i + 1))
add(dp[o ^ 1][i][j][p], dp[o][j][k][p]);
if(check(i, k, p, i + 1, i + 1))
add(dp[o ^ 1][i][k][p], dp[o][j][k][p]);
if(check(j, k, p, i + 1, i + 1))
add(dp[o ^ 1][j][k][p], dp[o][j][k][p]);
dp[o][j][k][p] = 0;
}
}
}
o ^= 1;
}
int res = 0;
for(int i = 0; i <= n; i++) {
for (int j = 0; j <= i; j++) {
for (int k = 0; k <= j; k++) {
add(res, dp[o][i][j][k]);
}
}
}
cout << res << 'n';
}
return 0;
}