[2021 CSP-S提高组] 题解(廊桥分配+括号序列+回文+交通规划)
2021 CSP-S 題解
- 廊橋分配
- 括號序列
- 回文
- 交通規劃
配合👉CSP-S游記 食用更佳哦~
【雷】:只是在民間數據過了,不保證一定正確。僅供參考!!!
【雷】:只是在民間數據過了,不保證一定正確。僅供參考!!!
【雷】:只是在民間數據過了,不保證一定正確。僅供參考!!!
廊橋分配
problem
題目鏈接
solution
顯然暴力就是枚舉國內的廊橋數量,然后模擬一遍,O(n2)O(n^2)O(n2)。
正解就是加速這個過程。
設 f1[i]:f_1[i]:f1?[i]: 國內有 iii 個廊橋能承載的飛機數量,fi[i]:f_i[i]:fi?[i]: 國外的。
最后就是 max?{f1[i]+f2[n?i]}\max\Big\{f_1[i]+f_2[n-i]\Big\}max{f1?[i]+f2?[n?i]}
考慮將 nnn 個廊橋看成 nnn 個桶,對于國內飛機,盡量地往前停,否則就再開一個廊橋停這個飛機,用前綴和就能求得 f1[i]/f2[i]f_1[i]/f_2[i]f1?[i]/f2?[i]。
可以通過 set\text{set}set 維護,迅速找到每架飛機著陸前空的廊橋。
code
#include <set> #include <cstdio> #include <iostream> using namespace std; #define maxn 100005 set < pair < int, int > > s; int f1[maxn], f2[maxn]; int n, m1, m2;void calc( int m, int *f ) {s.clear();for( int i = 1, x, y;i <= m;i ++ ) {scanf( "%d %d", &x, &y );s.insert( { x, y } );}for( int i = 1;i <= m;i ++ ) {auto it = s.begin();while( it != s.end() ) {f[i] ++;int k = it -> second;s.erase( it );it = s.lower_bound( { k + 1, 0 } );}f[i] += f[i - 1];} }int main() {scanf( "%d %d %d", &n, &m1, &m2 );calc( m1, f1 );calc( m2, f2 );int ans = 0;for( int i = 0;i <= n;i ++ )ans = max( ans, f1[i] + f2[n - i] );printf( "%d\n", ans );return 0; }括號序列
problem
題目鏈接
solution
這道題難就難在 **()** 是不合法的。
為了知道左右的信息,我們選擇區間 dpdpdp。
設 g[l,r]:[l,r]g[l,r]:[l,r]g[l,r]:[l,r] 能否全為 ?*?
設 f[l,r]:[l,r]f[l,r]:[l,r]f[l,r]:[l,r] 強制 l?rl-rl?r 括號匹配的方案數
設 dp[l,r]:[l,r]dp[l,r]:[l,r]dp[l,r]:[l,r] 為超級完美序列的方案數,不要求 l?rl-rl?r 一定匹配
轉移很簡單,就是將合法的規則翻譯成方程式即可。
- (***(...)) 枚舉左邊連續一段 ?*?
- ((...)***) 枚舉右邊連續一段 ?*?
- ((...)) 直接嵌套一個匹配括號對
- ()**() l?rl-rl?r 與不同的括號匹配,中間要么為 ?\empty? 要么為連續的 ?*?
主要是 dp?fdp-fdp?f 之間相互轉移,ggg 是預處理做的。
這就是妥妥的 O(n4)O(n^4)O(n4) 的轉移。
正解就是在這個基礎上進行了前綴和/后綴和的優化。
code-65’
#include <cstdio> #define maxn 505 #define int long long #define mod 1000000007 int n, m; char s[maxn]; int f[maxn][maxn], dp[maxn][maxn]; bool g[maxn][maxn];signed main() {scanf( "%lld %lld %s", &n, &m, s + 1 );for( int i = 1;i <= n;i ++ ) {if( s[i] == '*' or s[i] == '?' ) g[i][i] = 1;g[i][i - 1] = 1;}for( int len = 2;len <= m;len ++ )for( int i = 1;i + len - 1 <= n;i ++ ) {int j = i + len - 1;if( s[i] == '*' or s[i] == '?' ) g[i][j] |= g[i + 1][j];if( s[j] == '*' or s[j] == '?' ) g[i][j] |= g[i][j - 1];}for( int i = 1;i < n;i ++ )if( s[i] == ')' or s[i] == '*' or s[i + 1] == '(' or s[i + 1] == '*' ) continue;else f[i][i + 1] = dp[i][i + 1] = 1;for( int len = 3;len <= n;len ++ ) for( int i = 1;i + len - 1 <= n;i ++ ) {int j = i + len - 1;if( s[i] == ')' or s[i] == '*' or s[j] == '(' or s[j] == '*' ) continue;f[i][j] = ( f[i][j] + dp[i + 1][j - 1] ) % mod;if( j - 1 - ( i + 1 ) + 1 <= m ) f[i][j] = ( f[i][j] + g[i + 1][j - 1] ) % mod;for( int k = i + 2;k < j - 1;k ++ ) if( k - 1 - ( i + 1 ) + 1 > m ) break;else f[i][j] = ( f[i][j] + g[i + 1][k - 1] * dp[k][j - 1] ) % mod;for( int k = j - 2;k > i + 1;k -- )if( ( j - 1 ) - ( k + 1 ) + 1 > m ) break;else f[i][j] = ( f[i][j] + g[k + 1][j - 1] * dp[i + 1][k] ) % mod;for( int k = i + 1;k < j - 1;k ++ ) for( int t = 0;t <= m;t ++ )if( k + t + 1 >= j ) break;else dp[i][j] = ( dp[i][j] + f[i][k] * dp[k + t + 1][j] * g[k + 1][k + t] ) % mod;dp[i][j] = ( dp[i][j] + f[i][j] ) % mod;}printf( "%lld\n", dp[1][n] );return 0; }code-100‘
#include <cstdio> #include <iostream> using namespace std; #define int long long #define mod 1000000007 #define maxn 505 int f[maxn][maxn], g[maxn][maxn], h[maxn][maxn]; char s[maxn]; int n, m;bool is( int x, char c ) {if( x < 1 or x > n ) return 0;else return s[x] == '?' or s[x] == c; }signed main() {scanf( "%lld %lld %s", &n, &m, s + 1 );for( int i = 2;i <= n;i ++ ) f[i][i - 1] = 1;for( int l = n;l;l -- )for( int r = l;r <= n;r ++ ) {if( is( l, '(' ) and is( r, ')' ) ) {f[l][r] = f[l + 1][r - 1];for( int i = l + 2;i <= min( l + m + 1, r ) and is( i - 1, '*' );i ++ )f[l][r] = ( f[l][r] + f[i][r - 1] ) % mod;for( int i = r - 2;i >= max( l + 1, r - m - 1 ) and is( i + 1, '*' );i -- )f[l][r] = ( f[l][r] + f[l + 1][i] ) % mod;}h[l][r] = g[l][r] = f[l][r];for( int i = r - 1;i >= r - m and is( i + 1, '*' );i -- ) g[l][r] = ( g[l][r] + h[l][i] ) % mod;for( int i = l;i < r;i ++ ) f[l][r] = ( f[l][r] + g[l][i] * f[i + 1][r] ) % mod;}printf( "%lld\n", f[1][n] );return 0; }回文
problem
題目鏈接
solution
這道題比前面的題可能還要簡單一點。
會發現,每次選擇最左端或者最右端的數字,連續選擇對應在中間的序列也必須是連續的。
i.e.
1....213....3 選最左邊的 111,接著選最右邊的 333,bbb 序列里面就是 13...,為了最后的回文,最后幾次操作必須是選 333 后立馬選 111。
那會不會是 1...123....3 這種呢,123 貌似可以不相鄰成為兩端。
顯然不可能,先選的 13... 之后才選擇 222 ,那么回文就必須先選 222,再選 31,而 222 都被 111 和 333 堵死了。
所以這就是一個貪心模擬的過程。
優先從左邊選擇開始模擬。
code
#include <cstdio> #define maxn 1000005 int T, n, flag; int a[maxn], ans[maxn]; int pos[2][maxn];void print() {int l = 1, r = n << 1;for( int i = 1;i <= ( n << 1 );i ++ )if( ans[i] == l ) printf( "L" ), l ++;else printf( "R" ), r --;printf( "\n" ); }void solve( int l, int r, int L, int R ) {for( int i = 2;i <= n;i ++ ) {if( l < L ) {if( pos[1][a[l]] == L - 1 ) { ans[i] = l ++, ans[(n << 1 | 1) - i] = -- L; continue; }if( pos[1][a[l]] == R + 1 ) { ans[i] = l ++, ans[(n << 1 | 1) - i] = ++ R; continue; }}if( r > R ) {if( pos[0][a[r]] == L - 1 ) { ans[i] = r --, ans[(n << 1 | 1) - i] = -- L; continue; }if( pos[0][a[r]] == R + 1 ) { ans[i] = r --, ans[(n << 1 | 1) - i] = ++ R; continue; }}flag = 0;return;} }int main() {scanf( "%d", &T );while( T -- ) {scanf( "%d", &n );for( int i = 1;i <= n;i ++ ) pos[0][i] = pos[1][i] = 0;for( int i = 1;i <= ( n << 1 );i ++ ) {scanf( "%d", &a[i] );if( ! pos[0][a[i]] ) pos[0][a[i]] = i;else pos[1][a[i]] = i;}flag = 1;ans[1] = 1, ans[n << 1] = pos[1][a[1]];solve( 2, n << 1, pos[1][a[1]], pos[1][a[1]] );if( flag ) { print(); continue; }flag = 1;ans[1] = n << 1, ans[n << 1] = pos[0][a[n << 1]];solve( 1, (n << 1) - 1, pos[0][a[n << 1]], pos[0][a[n << 1]] );if( flag ) { print(); continue; }printf( "-1\n" );}return 0; }交通規劃
problem
題目鏈接
solution
只能黑白染色,然后端點顏色不同的邊就會計算貢獻。
如果想到了,就是非常明顯的網絡流。
這種平面圖般的網絡流是很經典的有最短路優化——BZOJ上有一題網絡流的經典“狼抓兔子”。
就算不會最短路優化也是可以暴力上網絡流硬跑前 60′60'60′ 的部分分。
code-60‘
#include <queue> #include <cstdio> #include <cstring> #include <iostream> using namespace std; #define inf 1e18 #define maxn 505 #define Maxn 260000 #define maxm 1200000 #define int long long queue < int > q; struct node { int to, nxt, flow; }E[maxm]; int n, m, T, cnt, N, s, t, k; int head[Maxn], cur[Maxn], dis[Maxn]; int a[maxn][maxn], b[maxn][maxn];void addedge( int u, int v, int flow ) {E[cnt] = { v, head[u], flow };head[u] = cnt ++;E[cnt] = { u, head[v], flow };head[v] = cnt ++; }bool bfs() {memset( dis, 0, sizeof( dis ) );dis[s] = 1, q.push( s );while( ! q.empty() ) {int u = q.front(); q.pop();for( int i = cur[u] = head[u];~ i;i = E[i].nxt ) {int v = E[i].to;if( ! dis[v] and E[i].flow ) {dis[v] = dis[u] + 1;q.push( v );}}}return dis[t]; }int dfs( int u, int cap ) {if( u == t or ! cap ) return cap;int flow = 0;for( int i = cur[u];~ i;i = E[i].nxt ) {cur[u] = i; int v = E[i].to;if( dis[v] == dis[u] + 1 ) {int w = dfs( v, min( cap, E[i].flow ) );if( ! w ) continue;E[i ^ 1].flow += w;E[i].flow -= w;flow += w;cap -= w;if( ! cap ) break;}}return flow; }int dinic() {int ans = 0;while( bfs() ) ans += dfs( s, inf );return ans; }int id( int i, int j ) { return ( i - 1 ) * m + j; }signed main() {scanf( "%lld %lld %lld", &n, &m, &T );for( int i = 1;i < n;i ++ ) for( int j = 1;j <= m;j ++ ) scanf( "%lld", &a[i][j] );for( int i = 1;i <= n;i ++ ) for( int j = 1;j < m;j ++ ) scanf( "%lld", &b[i][j] );while( T -- ) {cnt = 0, memset( head, -1, sizeof( head ) );scanf( "%lld", &k );N = n * m, s = N + k + 1, t = s + 1;for( int i = 1;i < n;i ++ ) for( int j = 1;j <= m;j ++ ) addedge( id(i, j), id(i + 1, j), a[i][j] );for( int i = 1;i <= n;i ++ ) for( int j = 1;j < m;j ++ ) addedge( id(i, j), id(i, j + 1), b[i][j] );for( int i = 1;i <= N;i ++ ) addedge( s, i, 0 ), addedge( i, t, 0 );for( int i = 1, w, x, c;i <= k;i ++ ) {scanf( "%lld %lld %lld", &w, &x, &c );++ N; int pos;if( x <= m ) pos = id( 1, x );else if( x <= n + m ) pos = id( x - m, m );else if( x <= n + m * 2 ) pos = id(n, 2 * m + n - x + 1);else pos = id( 2 * ( m + n ) - x + 1, 1 );addedge( N, pos, w );if( c ) addedge( s, N, w );else addedge( N, t, w );}printf( "%lld\n", dinic() );}return 0; }總結
以上是生活随笔為你收集整理的[2021 CSP-S提高组] 题解(廊桥分配+括号序列+回文+交通规划)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 别让大模型被基准评估坑了!测试集乱入预训
- 下一篇: 一加 12将完整搭载「新一代超光影影像系