[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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.tpcf.cn/news/316871.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

P1247 取火柴游戏

P1247 取火柴游戏 题意&#xff1a; 有n堆火柴&#xff0c;两个人轮流操作&#xff0c;每次只能在从一堆中取若干火柴&#xff0c;拿走最后一根火柴的为胜者&#xff0c;给你一个状态&#xff0c;问先手是赢是输 题解&#xff1a; 很经典的nim博弈&#xff0c;结论大家应该…

Codeforces:779(div2)

前言 solve 4 rnk247 占了罚时的便宜。 CF不占罚时便宜就会被罚时占便宜 感觉这场似乎都是性质题&#xff0c;一眼看出性质就秒了&#xff0c;看不出就很难做出来了。 C似乎卡了很多人。但我做起来还好。 D2做不出来有些懊恼。 E是妙题。 题目 A 水题&#xff0c;保证male…

我们为什么要搞长沙.NET技术社区(4)

我们为什么要搞长沙.NET技术社区&#xff08;4&#xff09;邹溪源&#xff0c;2019年3月7日Ps:文中的.NET 包括且不限定于传统.NET Framework技术和.NET Core技术。1. 楔子昨天&#xff08;2019年3月6日&#xff09;晚餐时间&#xff0c;有幸得到长沙技术圈资深.NET开发者出生…

P1290 欧几里德的游戏

P1290 欧几里德的游戏 题意&#xff1a; 给定两个正整数 M 和 N&#xff0c;从 Stan 开始&#xff0c;从其中较大的一个数&#xff0c;减去较小的数的正整数倍&#xff0c;当然&#xff0c;得到的数不能小于 0。然后是 Ollie进行同样的操作&#xff0c;直到一个人得到0&#…

【无码专区3】乘法表的解密破译

因为只有std&#xff0c;没有自我实现&#xff0c;所以是无码专区 problem 给定一个 qqq 进制的乘法表&#xff0c;每个字符代表着 0∼p−10\sim p-10∼p−1 不同的数字。 求每个字符代表的数字。保证有解。 \timesABCDACDBBDCBABBBBBBBBBCDCBBDBBCDBABBBCBD i.e. CD\text{C…

CF1553H XOR and Distance (Trie)

解析 有的时候&#xff0c;看起来是暴力的东西再稍微想想性质就是正解了。 本题有两种做法&#xff0c;一种使用了trie树&#xff0c;一种没有。但本质是一样的&#xff0c;只是trie树把我们的所求显性的表达了出来。 考虑trie树暴力怎么做。 对于一个特定的 xxx 走到一个结…

C#机器学习之判断日报是否合格

原文作者&#xff1a;心莱科技肖鑫简单来说机器学习的核心步骤在于“获取学习数据&#xff1b;选择机器算法&#xff1b;定型模型&#xff1b;评估模型&#xff0c;预测模型结果”&#xff0c;下面本人就以判断日报内容是否合格为例为大家简单的阐述一下C#的机器学习。第一步&a…

【无码专区4】幸运数字4(折半搜索+计数+结论)

因为只有std&#xff0c;没有自我实现&#xff0c;所以是无码专区 主要是为了训练思维能力 solution才是dls正解&#xff0c;但是因为只有潦草几句&#xff0c;所以大部分会有我自己基于正解上面的算法实现过程&#xff0c;可能选择的算法跟std中dls的实现不太一样。 std可能…

P1288 取数游戏II

P1288 取数游戏II 题意&#xff1a; 一个环&#xff0c;由边权&#xff0c;硬币一开始在一个点上&#xff0c;两个人轮流操作&#xff0c;每次操作向左或右移动&#xff0c;每次移动必须将边权减少到非负整数&#xff0c;如果原本是0则不能走&#xff0c;当不能走动时&#x…

CF1616F Tricolor Triangles(构造、高斯消元)

解析 关键性质&#xff1a;三元环合法等价于边权和模3等于0。 还有一个常识&#xff1a;三元环的级别是O(mm)O(m\sqrt m)O(mm​)。 证明&#xff1a; 三个点度数都大于 m\sqrt mm​ 的点不超过Cm3mmC_{\sqrt m}^3m\sqrt mCm​3​mm​ 个。 如果含有度数小于m\sqrt mm​ 的点&am…

SignalR2结合ujtopo实现拓扑图动态变化

上一篇文章基于jTopo的拓扑图设计工具库ujtopo&#xff0c;介绍了拓扑设计工具&#xff0c;这一篇我们使用SignalR2结合ujtopo实现拓扑图的动态变化。仅仅作为演示&#xff0c;之前的文章SignalR2简易数据看板演示&#xff0c;用一个小的示例演示了SignalR作为数据看板的用法&a…

树的同构模板题(法1.最小表示法+法2.树哈希)

树的同构problemsolutioncodesolutioncodeproblem 模板题 solution Ⅰ. 最小表示法 将树转化为 0/10/10/1 括号序列&#xff1a;从根开始 dfs\text{dfs}dfs&#xff0c;000 就往下遍历一个儿子&#xff0c;111 就返回&#xff0c;构成一个 2n2\times n2n 的括号序列。 显然…

CF917B MADMAX

CF917B MADMAX 题意&#xff1a; Alice和Bob有一个n个点m条边的DAG&#xff0c;每条边上有一个小写英文字母表示权值&#xff0c;Alice和Bob每人有一个棋子&#xff0c;每个人放在一个节点上&#xff08;可以放在同一个节点上&#xff09;。 第一轮Alice可以沿一条边把棋子移…

CF1534F:Falling Sand(tarjan、贪心、dp)

解析 本题做的过程大概是&#xff1a;到了正解门口决定回头&#xff0c;绕了地球一圈最后从另一边走到正解了… 我的分析&#xff1a; 首先 easy version 很简单&#xff0c;如果从一列最大值可以走到另一列最大值&#xff0c;那么后者就没用了。缩完点所有的零度点就是答案。…

Ocelot 入门Demo系列(01-Ocelot极简单Demo及负载均衡的配置)

来源&#xff1a;https://www.cnblogs.com/7tiny/p/10493805.html【前言】Ocelot是一个用.NET Core实现并且开源的API网关&#xff0c;它功能强大&#xff0c;包括了&#xff1a;路由、请求聚合、服务发现、认证、鉴权、限流熔断、并内置了负载均衡器与Service Fabric、Butterf…

CF464E The Classic Problem(主席树+哈希+最短路)

CF464E The Classic Problemproblemsolutioncodeproblem 题目链接 solution 经典题。 本题很特别的是每条边的边权都是 222 的幂&#xff0c;而且数据读入的是指数。 所以可以将路径权值看作一个二进制串&#xff0c;每加一条边就是对应二进制位 111&#xff0c;当然会有相…

CF1192B Dynamic Diameter(LCT)

Foreword\text{Foreword}Foreword zhengrunzhe 大佬的矩阵做法过于神奇&#xff0c;蒟蒻无法理解… 欧拉序的做法确实非常巧妙&#xff0c;但我也想不到这么神仙的做法… 提供一种可能简单一些的 LCT 做法。 由于本人 LCT 无法像大佬那么神&#xff0c;讲的会比较详细一些&…

博弈论(基础概念+例题)

博弈论(b站视频) 文章目录一些概念以Nim游戏为例Nim游戏介绍定义 必败/必胜局面必败/必胜局面的判定引理Nim游戏判定引理的等价命题有向图游戏对判定引理的数学描述-Sg函数有向图游戏的和题目&#xff1a;[有向图游戏][有向图游戏的和][构造/转化类]一些概念 以Nim游戏为例 Ni…

.NET Core 3.0 linux 部署小贴士

dotnet core 3.0 目前还是测试版&#xff0c;在linux下安装 sdk 需要有一些注意事项1.下载urlhttps://dotnet.microsoft.com/download/thank-you/dotnet-sdk-3.0.100-preview-009812-linux-x64-binaries2.安装指令mkdir -p $HOME/dotnet && tar zxf dotnet-sdk-3.0.100…

莓良心(第二类斯特林数)

莓良心problemsolutioncodeproblem 莓在执行任务时&#xff0c;收集到了 nnn 份岩浆能源&#xff0c;其中第 iii 份的能量值是 wiw_iwi​ &#xff0c;她 决定将它们分成恰好 kkk 组带回基地&#xff0c;每一组都要有至少 111 份能源。 每一组能源会对运输设备产生负荷值&…