自闭jpg. 就说说 PJ 吧。

TG炸的原因主要是因为PJ的炸裂以及T1……所以就直接分析根本原因了。

# 参考补题链接 #

# 推荐博客链接 #


0x00

考前一天晚上。

在LH巨佬家吃了饭,前往离HF大约1小时车程的NK边上的酒店。

到酒店收拾了一会儿,制订了个小计划,复习了不少板子。

像最短路,RMQ,LCA,EXGCD,euler啥的,都过了遍手。

当晚心态还是比较稳的,期待。

考试早上。

跟着大部队朦朦胧胧地到了NK门口。但好像一到门口就来精神了(?

然后在金牌讲师的带领下拍了OI生涯第一张比赛集体照。

接下来就在操场上等着进考场呗,期间遇到了几个外校的熟人,寒暄了几句。

进考场。

场地布置有点像ACM。

我还特别的注意到了以一种奇怪的方式折叠在天花板上的篮球框。

键盘,机器都还挺顺手的,不过座位刚好对着一条桌子腿,不是很舒服。

然后在裁判员宣读考试注意事项的时候,重新在脑袋里幻灯片了一下考试策略。(是的,我后面想起我考前还想过这玩意的


0x01

赛中。

T1一如既往的水。就直接每次暴力跑比n小的最大的二次幂即可。

5分钟打完调完过掉大样例跑去看T2。

T2就很迷惑了,想了半天只想出一个插排解法,心态直接就炸掉。但没办法,只能打完插排去看后面的题。一切炸的开始。

插排思路: 每次更新时二分找到之前的第i个位置,满足 a[i - 1] < x < a[i],将其插入,时间复杂度:你以为是 \(O(nlog_n)\) ?hhhhhh其实是 \(O(n^2)\)

T3感觉不可做,放掉,看T4。

T4第一眼好熟悉!马上反应是道dp,乱推了一堆通过单个二维转移的方程,没解出来。左看右看,考虑是不是最短路,结果直接随手把自己hack掉。最后打了个爆搜走人(我当时降智到直接没考虑记忆化。

再回去看T3,以为正解就是个暴力,后缀表达式乱搞交掉。

又跑去看T4,慌得要死,一直推到结束都没推出来。

最后五分钟T1刷了一个样例,感觉自己打错了,但其实是对的。于是魔改了一下,导致一中午都在担心自己好像没保存。

赛后。

一出考场就想起T4第二维两个循环转移。

一出考场就想起T2直接桶。。。(LH打树状数组过了,JC打对顶堆过了。

我谔谔,这次主要是心态炸锅了,太紧张了,导致一些白菜题没有切掉。

当然,后来反思也有考试策略有问题的成分。

估分:\(100\) \(+\) \(85\) \(+\) \(30\) \(+\) \(20\) \(=\) \(235\)。

实际能力极限:\(100\) \(+\) \(100\) \(+\) \(30\) \(+\) \(100\) \(=\) \(330\)。

以后做题还是应该再踏实一点,多做做思维题。

唉,好好复习NOIP吧。


0x02

题解部分

T1: (不再赘述。

#include <cstdio>

const int MAXN = 1e6 + 5;
int ans[MAXN], len = 0; int main() {
int n;
scanf ("%d", &n);
while(n) {
if(n == 1) {
printf("-1");
return 0;
}
long long t = 1;
while(t <= n)
t <<= 1;
if(t > n)
t >>= 1;
n -= t;
ans[++len] = t;
}
for(int i = 1; i < len; i++)
printf("%d ", ans[i]);
printf("%d", ans[len]);
return 0;
}

T2: (数据只到600?那毋庸置疑是个桶a。不要像我那样没看到600,导致只打了插排。

每次更新新的分数的时候,累加相对应的桶。

然后每次查找的时候,从大往小暴力找,找到分数线的位置直接输出即可。

时间复杂度:\(O(600n)\)

#include <cstdio>

inline int Max(int x, int y) {return x > y ? x : y;}
const int MAXN = 1e5 + 5;
const int MAXT = 605;
int a[MAXN], t[MAXT]; int main() {
int n, w;
scanf ("%d %d", &n, &w);
for(int i = 1; i <= n; i++) {
int x;
scanf ("%d", &x);
t[x]++;
int index = Max(1, i * w / 100), tot = 0, res = 0;
for(int j = 600; j >= 0; j--) {
tot += t[j];
if(tot >= index) {
res = j;
break;
}
}
printf("%d ", res);
}
return 0;
}

T3:(其实也不难想哦 可我还是不会

暴力就不提了吧。栈乱搞有30pt。个人认为这应该是最难的一道了。

至于正解,我们引入一个奇怪的字符树。

首先,你会发现整个表达式的取值只和一些特定的值有关,比如:

1 | (……) = 1;

0 & (……) = 0.

那么根据这个思路我们就可以考虑建树了嘛。实现看码。

时间复杂度:或许是 \(O(n + q)\) 吧。

#include <cstdio>
#include <stack>
#include <cstring>
using namespace std; const int MAXN = 1e6 + 5;
int a[MAXN], len = 0;
// a[]一组多用,下标 1 ~ n 为数集,n ~ 为符号集。
int cnt[MAXN], t[MAXN][2], Index = 0, n = 0;
// cnt-方便输入的数组,t 树,index 输入建树的下标。
bool vis[MAXN], q[MAXN];
// vis 表示这个数是否会决定表达式的答案,q 表示取反标记。
// vis 中,true 表示它不是决定性的,false 表示是决定性的。
char s[MAXN]; int dfs(int u, int f) {
// 在建树过程中顺便算出初始表达式的值。
// u 表示遍历,f 表示遍历时的取反标记。
a[u] ^= f; // 取反。
if(u <= n)
return a[u]; // 如果属于数集直接返回。
a[u] ^= f;
// 如果不属于数集,先取反回来,进行字符操作。
int x = dfs(t[u][0], (f ^ q[t[u][0]]));
int y = dfs(t[u][1], (f ^ q[t[u][1]]));
// 左右儿子遍历。
if(a[u] == -2) { // 如果是 &。
if(x == 0)
vis[t[u][1]] = 1;
if(y == 0)
vis[t[u][0]] = 1;
int res = (x & y);
return res;
}
else { // 如果是 |。
if(x == 1)
vis[t[u][1]] = 1;
if(y == 1)
vis[t[u][0]] = 1;
int res = (x | y);
return res;
}
} void update(int u) {
// 再扫一遍树。
// 我们之前只考虑了每个点的决定性情况。
// 但实际还应该考虑它的子树的决定性情况。
if (u <= n) return;
vis[t[u][0]] |= vis[u];
vis[t[u][1]] |= vis[u];
update(t[u][0]);
update(t[u][1]);
} int main() {
while(1) {
scanf ("%s", s);
if(s[0] >= '0' && s[0] <= '9') {
for(int i = 0; i < strlen(s); i++)
n = (n << 3) + (n << 1) + s[i] - '0';
break;
}
if(s[0] == 'x') {
int x = 0;
for(int i = 1; i < strlen(s); i++)
x = (x << 3) + (x << 1) + s[i] - '0';
cnt[++len] = x;
}
else if(s[0] == '|')
cnt[++len] = -1;
else if(s[0] == '&')
cnt[++len] = -2;
else if(s[0] == '!')
cnt[++len] = -3;
}
// 输入与一些保存方式。
Index = n;
for(int i = 1; i <= n; i++)
scanf ("%d", &a[i]);
stack<int> num;
// 后缀表达式-数字栈。
for(int i = 1; i <= len; i++) {
if(cnt[i] >= 0) { // 是数字。
num.push(cnt[i]);
continue;
}
switch(cnt[i]) {
case -1: { // 是 |。
int x = num.top();
num.pop();
int y = num.top();
num.pop();
Index++;
num.push(Index);
a[Index] = -1;
t[Index][0] = x;
t[Index][1] = y;
break;
}
case -2: { // 是 &。
int x = num.top();
num.pop();
int y = num.top();
num.pop();
Index++;
num.push(Index);
a[Index] = -2;
t[Index][0] = x;
t[Index][1] = y;
break;
}
case -3: { // 是 !。
q[num.top()] ^= 1;
break;
}
}
}
int Q, ans = dfs(Index, q[Index]);
update(Index);
scanf ("%d", &Q);
for(int i = 1; i <= Q; i++) {
int x;
scanf ("%d", &x);
printf("%d\n", vis[x] ? ans : (!ans));
}
return 0;
}

T4:(考场上降智了

一个数字三角形的变种。

其实就是需要多考虑一个从下往上走的情况,那就开两个dp更新嘛。

  • dp[i][j][1] 表示从下往上或从左往右走到 (i, j);
  • dp[i][j][0] 表示从上往下或从左往右走到 (i, j)。

这里指的是从上一步到这一步的状态。显然,答案就在 Max(dp[i][j][0], dp[i][j][1]) 里面。

然后就用类数字三角形的思路跑即可。

时间复杂度:\(O(nm)\)

#include <cstdio>
#include <cstring>
using namespace std; typedef long long LL;
inline LL Max(LL x, LL y) {return x > y ? x : y;}
const int MAXN = 1005;
const int INF = 0x3f3f3f3f;
LL dp[MAXN][MAXN][2];
int a[MAXN][MAXN]; int main() {
int n, m;
scanf ("%d %d", &n, &m);
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
scanf ("%d", &a[i][j]);
memset(dp, -INF, sizeof dp);
dp[1][0][0] = 0;
for(int j = 1; j <= m; j++) {
for(int i = 1; i <= n; i++)
dp[i][j][0] = Max(dp[i - 1][j][0], Max(dp[i][j - 1][1], dp[i][j - 1][0])) + a[i][j];
for(int i = n; i >= 1; i--)
dp[i][j][1] = Max(dp[i + 1][j][1], Max(dp[i][j - 1][1], dp[i][j - 1][0])) + a[i][j];
// 因为不能重复走所以 dp[i][j][0] 不能被 dp[i - 1][j][1] 更新,同理 dp[i][j][1] 不能被 dp[i + 1][j][0]更新。
// 那么就只需要将走到左边点的最优解与上面或下面可以用于更新的最优解比最大即可。
}
printf("%lld\n", dp[n][m][0]);
return 0;
}

就当是重新回到起跑线上,凡是过去,皆为序章。

CSP.2020的更多相关文章

  1. 【初赛】CSP 2020 第一轮(初赛)模拟记录

    感觉初赛不过关,洛谷上找了一套没做过的来练习. 顺便写了详细的题解. 试题用时:1h 单项选择: 第 1 题 十进制数 114 的相反数的 8 位二进制补码是: A.10001110 B.100011 ...

  2. 日记 + sb错误

    置顶消息cpdd 1.29 完了,文化课没了 我是废物 1.28 更新了自己的副标题 前副标题:Future never has to do with past time,but present ti ...

  3. Solution Set - 神奇 NOIP 模拟赛

    \[\mathfrak{\text{Defining }\LaTeX\text{ macros...}}\newcommand{\vct}[1]{\boldsymbol{#1}}\newcommand ...

  4. [游记]2020/CSP - S总结

    2020 / C S P − S 总 结 2020/CSP - S总结 2020/CSP−S总结 这年的 C S P CSP CSP考的不是很理想,本来稳进的 C S P − J CSP-J CSP− ...

  5. 2020 CSP&NOIP 游记

    CSP初赛 CSP初赛 Day -1 早上打了模拟赛,T2寒假正好做过,然而还是还是被踩Orz,郑外NB!.中午出校吃了大盘鸡和拉面,还带回来了三瓶可乐. 初赛知识点看了两页不(看)想(不)看(懂)了 ...

  6. CSP/S 2020 退役记

    上一次的AFO记 上上次的AFO记 Day -INF 一条咸鱼的垂死挣扎. RP+=INF Day 0 出发辣. 早上来到机房,带上了准备的面包和泡面....然而后来嫌太占地方就没拿...草了. 而且 ...

  7. CSP初赛复习

    初赛复习 初赛一定要过啊,否则付出的那么多都白搭了! while(1) ++csp.rp,++csp.luck,++csp.scores; 历史 2020年开始,除NOIP以外的NOI系列其他赛事(包 ...

  8. Spring Cloud--尚硅谷2020最新版

    Spring Cloud 初识Spring Cloud与微服务 在传统的软件架构中,我们通常采用的是单体应用来构建一个系统,一个单体应用糅合了各种业务模块.起初在业务规模不是很大的情况下,对于单体应用 ...

  9. NOIP 2020 游记

    第一次写比赛游记,请多多指教! I. 考前 由于最近参加了太多太多比赛了,所以没有敲模板题: 考前一周:主要是在做 AtCoder 的题和 xjoi 的模拟赛,相当于恶补了一些套路吧! 考前一天:上午 ...

随机推荐

  1. Java8新特性探索之Stream接口

    一.为什么引入Stream流 流是一系列与特定存储机制无关的元素--实际上,流并没有"存储"之说.使用流,无需迭代集合中的元素,就可以从管道提取和操作元素.这些管道通常被组合在一起 ...

  2. 用GitHub Pages搭建博客(一)

    什么是GitHub Pages GitHub官网介绍 GitHub Pages 官网是这样介绍的: Websites for you and your projects. 给你和你的项目的网站. Ho ...

  3. APIO2008免费道路

    题目大意 给定一张n个点m条边的图,图上有两种边,求保证有k条第一种边的情况下的最小生成树 传送门 题解 考虑最小生成树kruskal算法 先找到不含限制的最小生成树,然后就可以知道哪些第一种边是必选 ...

  4. 硬核卸载Vue(删除)

    第一步 查找vue位置 打开 cmd 输入 where vue 第二步 进入文件 直接cv(复制粘贴) 随便打开个文件 第三步 删除vue 删除前缀vue的所有 进入node_modules 删除@v ...

  5. 【Luogu】P1072 Hankson 的趣味题 题解

    原题链接 嗯...通过标签我们易得知,这是一道数学题(废话) 其中,题目给了这两个条件: \(gcd(x,a_0)=a_1,lcm(x,b_0)=b_1\) 所以,根据 \(gcd\) 与 \(lcm ...

  6. linux查看日志的几种方法

    linux 日志查看 tail.head. cat.tac.sed.less.echo 1.命令格式: tail       [必要参数]     [选择参数]     [文件] -f 循环读取 -q ...

  7. Serilog 源码解析——Sink 的实现

    在上一篇中,我们简单地查看了 Serilog 的整体需求和大体结构.从这一篇开始,本文开始涉及 Serilog 内的相关实现,着重解决第一个问题,即 Serilog 向哪里写入日志数据的.(系列目录) ...

  8. PHP博客

    创建数据库 用户表 blog_user userid int 用户id username varchar(50) 用户名 password varchar(30) 密码 type tinyint(2) ...

  9. ubuntu18.04下stlink的一种安装方法

    安装前准备: 从软件包存储库中安装以下软件包: git gcc或clang或mingw32-gcc或mingw64-gcc(C编译器:很可能已经存在gcc) build-essential (在基于D ...

  10. 面试官:Redis 主从复制时网络开小差了怎么整?

    上周因为实在太忙就认认真真写了一篇水文,吹了一下自己过去的经历,反响竟然超出了我的预期,并且后台还有读者留言表示想看续集的.哈哈,果然大家还是对水文更有热情. 这期我们继续回到之前的 Redis 话题 ...