http://acm.hdu.edu.cn/showproblem.php?pid=6578
不会做,看题解。
设dp[i][j][k][l]表示4种颜色出现的最后的位置分别是i,j,k,l的方法数,保证i>=j>=k>=l。其实不取=号,因为同一个位置不能放两个元素,除了开始的若干个比如dp[1][0][0][0]=4。
合法的转移叠加:
比如
刷新的颜色是i:dp[i+1][j][k][l]+=dp[i][j][k][l]
刷新的颜色是j:dp[i+1][i][k][l]+=dp[i][j][k][l]
刷新的颜色是k:dp[i+1][i][j][l]+=dp[i][j][k][l]
刷新的颜色是l:dp[i+1][i][j][k]+=dp[i][j][k][l]
假如从dp[i][j][k][l]转移到上述状态会导致新状态不满足约束则不进行这次转移,就太麻烦了。
由于是dp,其实只要遇到约束区间的右端点R的时候再考虑约束就可以了。
考虑四个数其实是[l,k,j,i],i肯定就是R,要是l>=L则有恰好4种颜色,否则要是k>=L则恰好3种颜色,否则要是j>=L则恰好2种颜色,否则只有1种颜色。
对每次转移后新状态的i维度必定是i+1,对i维度进行滚动节省空间。复杂度是精确的O(n^4+mn^3),据说很多队觉得过不了。
还卡memset???15组数据还卡memset?
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;inline int read() {int x = 0;char c = 0;while(c < '0' || c > '9')c = getchar();while(c >= '0' && c <= '9')x = (x << 3) + (x << 1) + c - '0', c = getchar();return x;
}inline void _write(int x) {if(x > 9)_write(x / 10);putchar(x % 10 + '0');
}inline void write(int x) {_write(x);putchar('\n');
}struct Condition {int l, r, x;bool operator<(const Condition &c)const {return r < c.r;}
} con[105];const int mod = 998244353;
int n, m, dp[2][105][105][105], ctop;inline void clear0(int n) {for(int j = 0; j <= n; ++j) {for(int k = 0; k <= j; ++k) {for(int l = 0; l <= k; ++l) {dp[n & 1][j][k][l] = 0;}}}
}inline void clear1(int i, int L) {//清除==1种的for(int j = L - 1 ; j >= 0; --j) {for(int k = j ; k >= 0; --k) {for(int l = k ; l >= 0; --l) {dp[i & 1][j][k][l] = 0;}}}
}inline void clear2(int i, int L) {//清除==2种的for(int j = i ; j >= L; --j) {for(int k = L - 1; k >= 0; --k) {for(int l = k ; l >= 0; --l) {dp[i & 1][j][k][l] = 0;}}}
}inline void clear3(int i, int L) {//清除==3种的for(int j = i ; j >= L ; --j) {for(int k = j ; k >= L; --k) {for(int l = L - 1; l >= 0; --l) {dp[i & 1][j][k][l] = 0;}}}
}inline void clear4(int i, int L) {//清除==4种的for(int j = i ; j >= L ; --j) {for(int k = j ; k >= L ; --k) {for(int l = k ; l >= L; --l) {dp[i & 1][j][k][l] = 0;}}}
}inline void update1(int i) {if(ctop > m || i < con[ctop].r)return;while(ctop <= m && i == con[ctop].r) {//printf("cons %d\n", ctop);int L = con[ctop].l, x = con[ctop].x;++ctop;if(x == 1) {clear2(i, L);clear3(i, L);clear4(i, L);} else if(x == 2) {clear1(i, L);clear3(i, L);clear4(i, L);} else if(x == 3) {clear1(i, L);clear2(i, L);clear4(i, L);} else {clear1(i, L);clear2(i, L);clear3(i, L);}}
}inline void update2(int i, int j, int k, int l) {dp[(i + 1) & 1][j][k][l] += dp[i & 1][j][k][l];if(dp[(i + 1) & 1][j][k][l] >= mod)dp[(i + 1) & 1][j][k][l] -= mod;dp[(i + 1) & 1][i][k][l] += dp[i & 1][j][k][l];if(dp[(i + 1) & 1][i][k][l] >= mod)dp[(i + 1) & 1][i][k][l] -= mod;dp[(i + 1) & 1][i][j][l] += dp[i & 1][j][k][l];if(dp[(i + 1) & 1][i][j][l] >= mod)dp[(i + 1) & 1][i][j][l] -= mod;dp[(i + 1) & 1][i][j][k] += dp[i & 1][j][k][l];if(dp[(i + 1) & 1][i][j][k] >= mod)dp[(i + 1) & 1][i][j][k] -= mod;
}int solve() {ctop = 1;memset(dp[1], 0, sizeof(dp[1]));dp[1][0][0][0] = 4;update1(1);for(int i = 1; i <= n - 1; ++i) {//printf("i=%d\n", i);clear0(i + 1);for(int j = i; j >= 0; --j) {for(int k = j ; k >= 0; --k) {if(k == j && k)continue;for(int l = k ; l >= 0; --l) {if(l == k && l)continue;update2(i, j, k, l);}}}update1(i + 1);for(int j = i; j >= 0; --j) {for(int k = j; k >= 0; --k) {if(k == j && k)continue;for(int l = k ; l >= 0; --l) {if(l == k && l)continue;//printf("dp[%d][%d][%d][%d]=%d\n", i + 1, j, k, l, dp[(i + 1) & 1][j][k][l]);}}}//printf("\n");}int ans = 0;for(int j = n - 1; j >= 0; --j) {for(int k = j ; k >= 0; --k) {for(int l = k ; l >= 0; --l) {ans += dp[n & 1][j][k][l];if(ans >= mod)ans -= mod;}}}return ans;
}
int main() {
#ifdef Yinkufreopen("Yinku.in", "r", stdin);
#endif // Yinkuint T = read();while(T--) {n = read(), m = read();for(int i = 1; i <= m; ++i) {con[i].l = read(), con[i].r = read(), con[i].x = read();}sort(con + 1, con + 1 + m);write(solve());}return 0;
}