题解:
首先,有一个不太直观的状态,f[i][j][k][l]表示DP到i位,三种颜色最后出现的位置分别是j, k, l的方案数。因为知道了三种颜色最后出现的位置,因此也可以得知以当前点为右端点的区间内有几种颜色了,因为左端点不断向左扩张的时候,颜色数不会减少。
然后考虑优化这个状态,观察到因为每一位都必须有一个颜色,所以这3种颜色当中最后出现的那个所在的位置一定是当前的i。因此我们就可以去掉i,所以复杂度变成了$n^3$,就可以过此题了。
每次转移之前判断一下是否满足当前右端点的限制,如果不满足就continue,否则枚举颜色转移即可。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define R register int 4 #define AC 302 5 #define ac 500 6 #define mod 1000000007 7 #define LL long long 8 9 int n, m; 10 int Head[AC], date[ac], Next[ac], len[ac], tot; 11 LL f[AC][AC][AC], ans; 12 13 inline int read() 14 { 15 int x = 0;char c = getchar(); 16 while(c > '9' || c < '0') c = getchar(); 17 while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); 18 return x; 19 } 20 21 inline void add(int f, int w, int S) 22 { 23 date[++tot] = w, Next[tot] = Head[f], Head[f] = tot, len[tot] = S; 24 } 25 26 inline void pre() 27 { 28 int a, b, c; 29 n = read(), m = read(); 30 for(R i = 1; i <= m; i ++) 31 { 32 a = read(), b = read(), c = read(); 33 add(b, a, c);//以右端点为标准 34 } 35 } 36 37 inline int Max(int x, int y, int z) 38 { 39 if(y > x) x = y; 40 if(z > x) x = z; 41 return x; 42 } 43 44 inline bool check(int x, int y, int z) 45 { 46 if(x && y && x == y) return false; 47 if(x && z && x == z) return false; 48 if(y && z && y == z) return false; 49 int k = Max(x, y, z); 50 for(R i = Head[k]; i; i = Next[i]) 51 { 52 int now = date[i], v = len[i], tmp = 0; 53 if(x >= now) ++ tmp; 54 if(y >= now) ++ tmp; 55 if(z >= now) ++ tmp; 56 if(tmp != v) return false; 57 } 58 return true; 59 } 60 61 void work() 62 { 63 f[0][0][0] = 1; 64 for(R i = 0; i <= n; i ++) 65 for(R j = 0; j <= n; j ++) 66 for(R l = 0; l <= n; l ++) 67 { 68 int k = Max(i, j, l); 69 if(!f[i][j][l]) continue; 70 //printf("(%d, %d, %d) = %lld\n", i, j, l, f[i][j][l]); 71 if(!check(i, j, l)) continue; 72 LL t = f[i][j][l]; 73 f[k + 1][j][l] = (f[k + 1][j][l] + t) % mod; 74 f[i][k + 1][l] = (f[i][k + 1][l] + t) % mod; 75 f[i][j][k + 1] = (f[i][j][k + 1] + t) % mod; 76 if(k == n) ans = (ans + f[i][j][l]) % mod;//必须到排到了n 77 } 78 printf("%lld\n", ans); 79 } 80 81 int main() 82 { 83 freopen("in.in", "r", stdin); 84 pre(); 85 work(); 86 fclose(stdin); 87 return 0; 88 }