2022.10.11 CSP-S 2021 测试总结

这场打的好心累, \(T1\) 想了 \(1\) 个多小时才想出来的, \(T2\),\(T4\)题意赛时还没读明白。

\(T1\):廊桥分配

\(T1\) 感觉是这几道题里最水的一道题,暴力都能踩过,然而却想了 \(1\) 个多小时的优化。首先我们考虑它是按照先来后到的顺序,那么一定会按照来的时间进行排序,那么很容易想到 \(O(n^2)\) 的做法,我们可以用 \(sum_i\) 代表在分配给 \(i - 1\) 个廊桥后又分配了一个所多飞机数,那么我们每次只需要暴力的找到每个廊桥是否符合当前的飞机即可。但是数据给到了 \(1e5\),怎么优化呢?我们可以用一个 \(set\),将每个飞机到达的时间扔到 \(set\) 里,然后我们在用一个 \(map\) 存一下每个飞机的离开时间即可,这样我们就可以二分查找到符合的飞机了,并且很容易删除掉符合的飞机。

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int M = 1e5 + 7;
set<int> s , ss;
unordered_map<int,int> a , b;
int sum1[M] , sum2[M];
signed main () {
freopen("airport.in","r",stdin);
freopen("airport.out","w",stdout);
ios::sync_with_stdio(0),cin.tie(0);
int n , m1 , m2;
cin >> n >> m1 >> m2;
int cnt = 0 ,sum =0 ;
for(int i = 1; i <= m1; ++ i) {
int l , r; cin >> l >> r;
a[l] = r;
s.insert(l);
}
s.insert(0x3f3f3f3f);
while(cnt < m1) {
sum ++;
int x;
for(auto i : s) {
x = i;
break;
}
while(x < 1e9) {
sum1[sum] ++;
cnt ++;
s.erase(x);
x = a[x];
x = *s.lower_bound(x);
}
}
for(int i = 1; i <= n; ++ i) sum1[i] += sum1[i - 1];
cnt = 0 , sum = 0;
for(int i = 1; i <= m2; ++ i) {
int l , r; cin >> l >> r;
b[l] = r;
ss.insert(l);
}
ss.insert(0x3f3f3f3f);
while(cnt < m2) {
sum ++;
int x;
for(auto i : ss) {
x = i;
break;
}
while(x < 1e9) {
sum2[sum] ++;
cnt ++;
ss.erase(x);
x = b[x];
x = *ss.lower_bound(x);
}
}
int ans = 0;
for(int i = 1; i <= n; ++ i) sum2[i] += sum2[i - 1];
for(int i = 0; i <= n; ++ i) ans = max(ans , sum1[i] + sum2[n - i]);//这里是从0开始!
cout << ans << '\n';
}

\(T2\):括号序列

\(T2\) 好难。赛时的时候打了个爆搜结果发现题读假了,然后果断放弃了。等作者写出来再来补吧。补出来了(看的题解)。这道题的难点在于读题和对于合法串的 \(check\),首先我们考虑什么样的串是合法的,如 \((*(*)*)\) 就不是一个合法的序列,\((*(*)(*)*)\)也不是,而 \((*(*)*(*))\) 则是一个合法的序列,为什么呢,因为我们可以将 \((*)*(*)\) 看做一个合法序列 \(A\),则变成了 \((*A)\),这样他就合法了,而前两种都无法通过转化变成这种。那怎么做呢。首先很容易想到爆搜,每次试填,复杂度大概是 \(O(3^n)\) 的,那怎么办采取优化呢,我们发现 \(n \le 500\),很像一个区间 \(dp\),那我们是否可以采取类似于区间 \(dp\) 的方法呢。答案是肯定的。我们首先要明确几种状态,下面用数字代替了

	0:****...*****
编号为0的是全是 * 的情况
1:(.........)
编号为1是外面套一个括号的情况
2:(...)**..**(..)**..**
编号为2是以括号开头,以 * 结尾的情况
3:(..)**..**(..)**..**(..)
编号为3是以括号开头,以括号结尾的情况
4:**(..)**..**(..)
编号为4是以 * 开头以括号结尾的情况
5:**(..)**(..)**
编号为5是以 * 开头并结尾的情况(0是特殊的5的情况)

这样我们就可以很容易的进行 \(dp\) 设计了,我们令 \(f_{i,j,k}\) 为 \(l\) ~ \(r\) 区间内为编号 \(k\) 的方案数。我么可以得到转移方程:

\(f_{i,j,0}\)

直接特判即可

\(f_{i,j,1}\) \(=\) \(f_{i+1,l-1,0} + f_{i+1,l-1,2}+f_{i+1,l-1,3}+f_{i+1,l-1,4}\),

但是我们需要特判一下是否可以嵌套上括号

\(f_{i,j,2}\) \(=\) \(\sum_{l=i}^{j-1}f_{i,l,3} * f_{l + 1,0}\)

\(f_{i,j,3}\) \(=\) \(\sum_{l=i}^{j-1}(f_{i,l,3}+f_{i,l,2})*f_{l+1,j,1}+f_{i,j,1}\)

注意编号为 \(1\) 也是以括号开头和结尾的,也需要加上

\(f_{i,j,4}\) \(=\) \(\sum_{l=i}^{j-1}(f_{i,l,4}+f_{i,l,5})*f_{l+1,j,0}\)

\(f_{i,j,5}\) \(=\) \(\sum_{l=i}^{j-1}f_{i,l,4}*f_{l+1,j,0}\)

然后放一个简短的代码吧

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int M = 5e2 + 7 , mod = 1e9 +7;;
int f[M][M][6];
char s[M];
bool check(int l , int r) {return (s[l] == '(' || s[l] == '?') && (s[r] == ')' || s[r] == '?');}
signed main () {
int n , m; cin >> n >> m;
cin >> s + 1;
for(int i = 1; i <= n; ++ i) f[i][i - 1][0] = 1;
for(int i = 1; i <= n; ++ i) {
for(int j = 1; j <= n - i + 1; ++ j ){
int k = j + i - 1;
if(i <= m) f[j][k][0] = f[j][k - 1][0] && (s[k] == '*' || s[k] == '?');
if(i >= 2) {
if(check(j , k)) f[j][k][1] = (f[j + 1][k - 1][0] + f[j + 1][k - 1][2] + f[j + 1][k - 1][4] + f[j + 1][k - 1][3]) % mod;
for(int l = j; l <= k - 1; ++ l) {
f[j][k][2] = (f[j][k][2] + f[j][l][3] * f[l + 1][k][0] % mod) % mod;
f[j][k][3] = (f[j][k][3] + (f[j][l][2] + f[j][l][3]) * f[l + 1][k][1]% mod) % mod;
f[j][k][4] = (f[j][k][4] + (f[j][l][4] + f[j][l][5]) * f[l + 1][k][1]% mod) % mod;
f[j][k][5] = (f[j][k][5] + f[j][l][4] * f[l + 1][k][0] % mod) % mod;
}
}
f[j][k][5] = (f[j][k][5] + f[j][k][0]) % mod;
f[j][k][3] = (f[j][k][3] + f[j][k][1]) % mod;
}
}
cout << f[1][n][3];
}

\(T3\):回文

\(T3\) 比 \(T2\) 简单太多了。但是作者太弱了,赛时只想出来了一个爆搜。对于 \(a\) 数组,我们最先开始只能掐头或去尾,那么我们的第一个操作就知道了,下面我们只考虑第一步取开头的情况,我们设开头数字为 \(x\),我们考虑回文串的性质,那么最后一个操作是将另一个开头或结尾的数字扔到 \(b\) 数组里,所以我们考虑找到第二个 \(x'\),这样我们只需要在 \(x\) 与 \(x'\) 中间插入其他数就可以了。那么如何维护其他数呢?因为两个一样的数不能连续取,所以一定有一个在前一个在后,所以我们可以考虑用栈来处理,我们可以将在 \(x'\) 左边的数放到第一个栈 \(s_1\) ,右边的放到第二个栈 \(s_2\),那么我们会发现如果一个数是两个栈的栈顶,另一个在栈底,那么他们两个可以组成回文。我们只需每次判断栈顶是否符合,然后将栈底上移即可。但题目中又要求字典序最小,所以我们优先做 \(x'\) 左侧的,但是对于在不同的两个栈的数,我们会让取右侧的数尽量在后即可。

view code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int M = 1e6 + 7;
int a[M] , s1[M] , s2[M] , top1 , top2 , vis[M] , last1 , last2 , ans[M];
signed main () {
freopen("palin2.in","r",stdin);
freopen("out.out","w",stdout);
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int t; cin >> t;
while(t -- ) {
int n; cin >> n;
top1 = 0 , top2 = 0;
last1 = 1 , last2 = 1;
for(int i = 1; i <= 2 * n; ++ i) cin >> a[i];
int pos;
for(int i = 2; i <= 2 * n; ++ i) {
if(a[i] == a[1]) {pos = i; break;}
}
for(int i = pos - 1; i > 1 ; -- i) s1[++ top1] = a[i];
for(int i = pos + 1; i <= 2 * n; ++ i) s2[++ top2] = a[i];
int cnt = 1;
while(cnt <= n) {
if(s2[last2] == s1[top1] && last2 <= top2 && top1 >= last1) {
last2 ++;
ans[++ cnt] = 1 , ans[2 * n - cnt + 1] = 2;
top1 --;
}
else if(s1[last1] == s1[top1] && top1 > last1) {
last1 ++;
ans[++ cnt] = 1 , ans[2 * n - cnt + 1] = 1;
top1 --;
}
else if(s2[last2] == s2[top2] && last2 < top2) {
last2 ++;
ans[++ cnt] = 2 , ans[2 * n - cnt + 1] = 2;
top2 --;
}
else if(s1[last1] == s2[top2] && top2 >= last2 && last1 <= top1) {
last1 ++;
ans[++ cnt] = 2 , ans[2 * n - cnt + 1] = 1;
top2 --;
}
else break;
}
if(cnt == n) {
ans[1] = 1;
ans[2 * n] = 1;
for(int i = 1; i <= 2 * n; ++ i)
if(ans[i] == 1) cout << 'L';
else if(ans[i] == 2) cout << 'R';
cout << '\n';
continue;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
top1 = 0 , top2 = 0;
last1 = 1 , last2 = 1;
for(int i = 1; i <= 2 * n; ++ i) {
if(a[i] == a[n * 2]) {pos = i; break;}
}
for(int i = pos - 1; i > 0 ; -- i) s1[++ top1] = a[i];
for(int i = pos + 1; i < 2 * n; ++ i) s2[++ top2] = a[i];
cnt = 1;
while(cnt <= n) {
if(s2[last2] == s1[top1] && last2 <= top2 && top1 >= last1) {
last2 ++;
ans[++ cnt] = 1 , ans[2 * n - cnt + 1] = 2;
top1 --;
}
else if(s1[last1] == s1[top1] && top1 > last1) {
last1 ++;
ans[++ cnt] = 1 , ans[2 * n - cnt + 1] = 1;
top1 --;
}
else if(s2[last2] == s2[top2] && last2 < top2) {
last2 ++;
ans[++ cnt] = 2 , ans[2 * n - cnt + 1] = 2;
top2 --;
}
else if(s1[last1] == s2[top2] && top2 >= last2 && last1 <= top1) {
last1 ++;
ans[++ cnt] = 2 , ans[2 * n - cnt + 1] = 1;
top2 --;
}
else break;
}
if(cnt == n) {
ans[1] = 2;
ans[2 * n] = 1;
for(int i = 1; i <= 2 * n; ++ i)
if(ans[i] == 1) cout << 'L';
else if(ans[i] == 2) cout << 'R';
cout << '\n';
continue;
}
cout << -1 << '\n';
}
}

\(T4\):交通规划

\(T4\) 就算了吧,我不配了。

2202.10.11 CSP-S 2021 测试总结的更多相关文章

  1. Noip模拟74 2021.10.11

    T1 自然数 考场上当我发现我的做法可能要打线段树的时候,以为自己百分之百是考虑麻烦了 但还是打了,还过掉了所有的样例,于是十分自信的就交了 正解还真是线段树,真就第一题数据结构 但是包括自己造的小样 ...

  2. 2019.10.26 CSP%您赛第三场

    \(CSP\)凉心模拟^_^ --题源\(lqx.lhc\)等各位蒟蒻 题目名称 比赛 传递消息 开关灯 源文件名 \(competition.cpp\) \(message.cpp\) \(ligh ...

  3. iOS冰与火之歌(番外篇) - 基于PEGASUS(Trident三叉戟)的OS X 10.11.6本地提权

    iOS冰与火之歌(番外篇) 基于PEGASUS(Trident三叉戟)的OS X 10.11.6本地提权 蒸米@阿里移动安全 0x00 序 这段时间最火的漏洞当属阿联酋的人权活动人士被apt攻击所使用 ...

  4. 背水一战 Windows 10 (11) - 资源: CustomResource, ResourceDictionary, 加载外部的 ResourceDictionary 文件

    [源码下载] 背水一战 Windows 10 (11) - 资源: CustomResource, ResourceDictionary, 加载外部的 ResourceDictionary 文件 作者 ...

  5. HP 820 G2变色龙安装10.11.6基本完美

    初始状态: 一块ssd硬盘,MBR格式分区,安装了WIN7 64位. 不想动win系统,因此就安装在硬盘的扩展分区 电脑配置: cpu: i7-5600u 声卡: ALC280 显卡: HD55 ...

  6. MAC OS升级到10.11(OS X EICAPTION)之后CocoaPods不能正常使用的问题解决

    昨晚回家之后开始升级系统到10.11,下载了一整个晚上之后终于在早上下载完毕,早上带到公司,想查一个第三方库的时候却遇到了问题: guoyufudeMacBook-Pro:~ GuoYufu$ pod ...

  7. 释放修改OS X 10.11系统文件权限【转】

    序言:有时要替换相关的(系统目录下的)文件以完成软件的破解,但在 OS X 10.11 系统图形界面下,Root(系统超级用户)已‘转变’为 Administrator(管理员用户),选择系统文件夹( ...

  8. macosx 10.11 python pip install 出现错误OSError: [Errno 1] Operation not permitted:

    Exception: Traceback (most recent call last): File , in main status = self.run(options, args) File , ...

  9. 战神Z7 D2安装黑苹果OS X El Capitan 10.11.2

    安装之初状态:两块硬盘,都是MBR格式分区,一块是机械硬盘,安装了WIN7 32位和Linux,一块是SSD,安装的是WIN7 64位与WIN10 64位以前玩过Mavericks,安装的就是在硬盘的 ...

  10. [原创]Mac系统下制作OS 10.11安装镜像

    一.所需软件 1.从App Store下载OS X El Capitan 10.11.2 ------------------------------------------------------- ...

随机推荐

  1. Xcode 12.x下载了iOS10.x模拟器无法创建对应Device问题修复

    转自: https://hiraku.tw/2021/04/6428/ 感谢原作者,如有侵权请评论联系删除文章 在升級到 Xcode 12 之後,有些人發現雖然 Xcode 允許安裝低版本的模擬器,但 ...

  2. Visio中的图无失真导入LaTeX中

    参考网址: LaTeX导入图片不失帧的方法_奋斗的西瓜瓜的博客-CSDN博客_latex图片模糊 LaTeX中插入eps格式图片_不觉岁华成暗度的博客-CSDN博客_eps latex Visio图片 ...

  3. Raid磁盘阵列更换磁盘时另一块盘离线恢复案例(v7000存储数据恢复)

    Raid磁盘阵列更换磁盘时另一块盘离线恢复案例(v7000存储数据恢复) [故障描述]客户设备型号为IBM V7000存储,架构为AIX+oracle+V7000存储阵列柜,需要恢复的数据主要存放在阵 ...

  4. git技能树总结

    1. git简介 版本控制: 指的是一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统.版本控制系统发展可分三个阶段:本地版本控制系统 -> 集中式版本控制系统 -> 分布 ...

  5. JAVA学习笔记-09

    多线程: 进程:就是正在执行中的程序,每一个进程执行都有一个执行的顺序,该顺序是一个执行路径.或者叫一个控制单元. 线程:就是进程中的一个独立的控制单元,线程在控制着进程的执行 一个进程中至少有一个线 ...

  6. Redis实战(三)Redis冷备如何做

    Redis 的 RDB 持久化方案,相信大家都有所了解,但是对于企业来说,如果只是持久化了一个 RDB 文件,不足以应付生产级别的事故.通常的方案就是对 RDB 进行多个备份,今天带大家来真枪实弹操作 ...

  7. ROS-安装与开发速记

    参考教程: B站视频(感谢赵老师):https://www.bilibili.com/video/BV1Ci4y1L7ZZ?p=14&spm_id_from=pageDriver 课程文件:h ...

  8. 《计算机是怎么跑起来的》第十章 XML(可扩展标记语言)

    资料来源 (1) <计算机是怎么跑起来的> 注1:XML是Extensible Markup Language(可扩展标记语言)的缩写; 1.XML是标记语言 (1) 通常把通过添加标签为 ...

  9. 微信小程序-通过绑定事件进行传值

    一.数据绑定: <view bindtap="node" data-num="5"> 点击传值:{{nums}} </view> dat ...

  10. Android Studio的xml文件无法代码提示

    之前试了省电模式.清理缓存.重新勾选sdk都没有任何用 于是我开始乱搞,总结了以下方法: 找到Gradle Script中的build.gradle(Module:XXXX) 修改compileSdk ...