ARC074 E RGB Sequence DP

~~~题面~~~

题解:

  首先,有一个不太直观的状态,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 }
View Code

 

转载于:https://www.cnblogs.com/ww3113306/p/9751683.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值