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. elasticsearch 排错总结

    控制台乱码 修改elasticsearch-7.6.2\config下的jvm.options文件,在任意行上加上 -Dfile.encoding=GBKIK报错但成功启动,按照网上的说法是jdk权限 ...

  2. C盘爆红满了怎么办?既然C盘装不下了,那咱给C盘扩容不就完事了吗!

    我们在使用电脑的过程中,经常容易出现C盘爆红,反而其他盘还有大量可用空间的情况. 为什么会这样呢?其实主要就两种原因: 一是电脑使用习惯不好,不管什么软件都默认安装在C盘,大文件又喜欢放在桌面,久而久 ...

  3. vue项目打包后,自由修改配置如接口地址等

    背景描述: 项目打包后,如果想更换接口域名或者项目名称,就需要再次打包.但是这样子操作有点耗费时间.如果把这些配置写到一个文件中,然后在index.html文件中引入使用,这样子会大大提高工资效率,节 ...

  4. 通过系统函数分配内存sbrk/sbrk

    #include <unistd.h> #include <stdio.h> int main(void) { printf("================brk ...

  5. libnode使用addon

    自己编译的一个libnode.so后,在js里调用hello.node的 addon时候会报错. Error: dlopen failed: cannot locate symbol "na ...

  6. c++中内联函数和宏函数的区别

    一. 区别: 是不是函数: 宏定义不是函数,但是使用起来像函数.预处理器用复制宏代码的方式代替函数的调用,省去了函数压栈退栈过程,提高了效率: 内联函数本质上是一个函数,内联函数一般用于函数体的代码比 ...

  7. NOI 1.7编程基础之字符串

    11:潜伏者 1.描述 R国和S国正陷入战火之中,双方都互派间谍,潜入对方内部,伺机行动. 历经艰险后,潜伏于S国的R国间谍小C终于摸清了S国军用密码的编码规则: 1.    S国军方内部欲发送的原信 ...

  8. C盘满了

      今天电脑提示说C盘磁盘满了,于是开始做磁盘清理 右击C盘,点管理. 点击磁盘清理,勾选中临时文件.下载.回收站.缩略图,然后点击清理系统文件. 再去查看C盘仍然没有多大变化,于是挨个翻看C盘到底哪 ...

  9. 1.java 开始

    WelloWorld 随便新建一个文件夹,存放代码 新建一个java文件 编写代码 编译javac java文件,生成一个class文件 运行class文件,java class 可能遇到的情况 每个 ...

  10. Docker的资源限制

    CPU CGROUP MEM CGROUP Storage 默认的overlay fs不支持配额,需要底层文件系统如xfs,ext4的支持. 在docker中启用示例如下,限制单个容器最大使用空间为2 ...