CodeForces 567F DP Mausoleum
本著只貼代碼不寫分析的題解是在耍流氓的原則,還是決定寫點分析。
思路很清晰,參考的官方題解,一下文字僅對題解做一個簡要翻譯。
?
題意:
有1~n這n個數,每個數用兩次。構成一個長為2n的序列,而且要求序列滿足先遞增后遞減(都是非嚴格的遞增遞減)。
再給出k個約束,每個約束形如1 >= 3這種,表示序列的第一個數要不小于第三個數。
問滿足約束的合法序列有多少種。
?
分析:
首先先不考慮這些約束條件,考慮如何構造出這種序列。
考慮兩個1放置的位置,因為序列是兩邊小中間大,所以這兩個1要么放在前面兩個位置,或者后面兩個位置,要么一前一后,而且只有這三種放法。
事實上,不考慮約束條件的話,n個數能得到的合法的序列的個數為3n
?
因此這些數是1~n從兩邊往中間放的。
設d(L, R)表示[L, R]這個區間還沒放數,滿足約束條件的序列個數,則答案為d(1, 2n)
下面考慮如何處理這些不等式:
計算d(L, R)時,比如要放在L和L+1這兩個格子,那么就考慮所有和L相關的不等式,以及和L+1相關的不等式。
為了更清楚起見,畫一個圖看看:
綠色表示已經放好數的區間,黃色表示正要放的兩個格子,紅色是還未放數的區間。
那么有大小關系:綠色的數 < 黃色的數 < 紅色的數,兩個黃色格子的數是相等的。
比如有不等式L >= v
如果a[L] == a[v],那么v應該等于L + 1,表示L和v兩個位置放同一個數;
如果a[L] > a[v],那么v應該在綠色的區間表示之前已經放過數了,這樣放在L的數才能比放在v的數大。
?
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <vector> 6 #include <map> 7 #define MP make_pair 8 using namespace std; 9 10 typedef long long LL; 11 12 const int maxn = 80; 13 14 int n, k; 15 16 vector<int> G[maxn], req[maxn]; 17 18 LL d[maxn][maxn]; 19 20 bool check(int L, int R, int l, int r) 21 { 22 for(int i = 0; i < G[l].size(); i++) 23 { 24 int v = G[l][i], t = req[l][i]; 25 if(t == -2) 26 { 27 if(v < L || v > R || v == r) return false; 28 } 29 else if(t == -1) 30 { 31 if(v < L || v > R) return false; 32 } 33 else if(!t) 34 { 35 if(v != r) return false; 36 } 37 else if(t == 1) 38 { 39 if(v >= L && v <= R && v != r) return false; 40 } 41 else 42 { 43 if(v >= L && v <= R) return false; 44 } 45 } 46 47 for(int i = 0; i < G[r].size(); i++) 48 { 49 int v = G[r][i], t = req[r][i]; 50 if(t == -2) 51 { 52 if(v < L || v > R || v == l) return false; 53 } 54 else if(t == -1) 55 { 56 if(v < L || v > R) return false; 57 } 58 else if(!t) 59 { 60 if(v != l) return false; 61 } 62 else if(t == 1) 63 { 64 if(v >= L && v <= R && v != l) return false; 65 } 66 else 67 { 68 if(v >= L && v <= R) return false; 69 } 70 } 71 72 return true; 73 } 74 75 LL dp(int L, int R) 76 { 77 LL& ans = d[L][R]; 78 if(ans >= 0) return d[L][R]; 79 if(L + 1 == R) 80 { 81 if(check(L, R, L, R)) return 1LL; 82 return 0; 83 } 84 85 ans = 0; 86 87 if(check(L, R, L, L + 1)) 88 ans += dp(L + 2, R); 89 if(check(L, R, L, R)) 90 ans += dp(L + 1, R - 1); 91 if(check(L, R, R - 1, R)) 92 ans += dp(L, R - 2); 93 94 return ans; 95 } 96 97 int main() 98 { 99 scanf("%d%d", &n, &k); 100 char eq[10]; 101 while(k--) 102 { 103 int u, v; 104 scanf("%d", &u); 105 scanf("%s", eq); 106 scanf("%d", &v); 107 108 int t; 109 if(strcmp(eq, "<") == 0) t = -2; 110 else if(strcmp(eq, "<=") == 0) t = -1; 111 else if(strcmp(eq, "=") == 0) t = 0; 112 else if(strcmp(eq, ">=") == 0) t = 1; 113 else if(strcmp(eq, ">") == 0) t = 2; 114 else exit(1234); 115 116 if(u == v) 117 { 118 if(abs(t) <= 1) continue; 119 else { puts("0"); exit(0); } 120 } 121 122 req[u].push_back(t); req[v].push_back(-t); 123 G[u].push_back(v); G[v].push_back(u); 124 } 125 126 memset(d, -1, sizeof(d)); 127 128 printf("%I64d\n", dp(1, n * 2)); 129 130 return 0; 131 } 代碼君?
轉載于:https://www.cnblogs.com/AOQNRMGYXLMV/p/4738710.html
總結
以上是生活随笔為你收集整理的CodeForces 567F DP Mausoleum的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: BZOJ 1055 [HAOI2008]
- 下一篇: Hibernate 一对一注释