赛时过了 A-E,然后就开摆了,为什么感觉 C 那么无厘头[发怒][发怒]

排名:25th

A.Game with Board

题目描述:

Alice 和 Bob 玩游戏,他们有一块黑板。最初,有 \(n\) 个整数 \(1\)。Alice 和 Bob 轮流操作,Alice 先手。

轮到时,玩家必须在棋盘上选择几个(至少两个)相等的整数,擦除它们,然后写一个等于它们总和的新整数。

如果玩家不能移动(棋盘上的所有整数都不同),该玩家将赢得游戏。

如果两名选手都发挥最佳,则确定谁获胜。

题目分析:

可以发现当 \(n > 4\) 时,Alice 可以一步让其变成 \(n-2,1,1\) 这三个数,且 Bob 下一步只可以将两个 \(1\) 变成 \(2\),局面变成 \(n-2,2\) Alice 就必胜。

对于 \(n \le 4\) 的情况,手动模拟发现 \(Bob\) 必胜。

代码:

点击查看代码
#include<bits/stdc++.h>
using namespace std;
int main(){
int T;scanf("%d",&T);
while(T--){
int n;scanf("%d",&n);
if(n == 2 || n == 3 || n == 4) printf("Bob\n");
else printf("Alice\n");
}
return 0;
}

B.Keep it Beautiful

题目描述:

定义一个序列是漂亮的,当且仅当存在 \(k \in [0,n-1]\) 使得 \(a_{k+1},a_{k+1},\cdots,a_n,a_1,a_2,\cdots,a_k\) 单调不降

特别的如果序列长度为 \(0\) 或 \(1\) 则它也是漂亮的。

初始时给定序列为空,给定 \(q\) 次操作每次在序列末尾插入数 \(x\),若插入之后序列仍为漂亮的则插入这个数,否则不插入这个数。

判断每一次操作是否可能插入这个数。

多测 \(t \le 10^4,\sum q \le 2·10^5\)

题目分析:

如果我们序列就是单调不降的当然没必要断开,那么如果断开意味着我们断的肯定是单调下降的位置,因为这样才可能使得满足单调不降的条件。

所以如果存在两个位置单调下降则不合法,或者存在一个位置单调下降且首尾拼起来的位置单调下降则不合法。

所以就扫一遍判就好了。

代码:

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+5;
int a[N],b[N];
int main(){
int T;scanf("%d",&T);
while(T--){
int n;scanf("%d",&n);
for(int i=1; i<=n; i++) scanf("%d",&a[i]);
int tot = 0,tmp = 0;
for(int i=1; i<=n; i++){
if(tot == 0) b[++tot] = a[i],printf("1");
else{
if(tmp + (a[i] < b[tot]) + (b[1] < a[i]) > 1) printf("0");
else tmp = tmp + (a[i] < b[tot]),b[++tot] = a[i],printf("1");
}
}
printf("\n");
}
return 0;
}

C.Ranom Numbers

题目描述:

Ranom Number 是一个字符串,这个字符串只含字母 \(\texttt A \sim \texttt E\)。\(\texttt{A}\) 的值是 \(1\),\(\texttt{B}\) 的值是 \(10\),\(\texttt{C}\) 的值是 \(100\),\(\texttt{D}\) 的值是 \(1000\),\(\texttt{E}\) 的值是 \(10000\)。

这个串的值按如下规则计算:如果一个字母的右侧没有值严格大于它的字母,那么它对串的值贡献为正的该字母的值,否则贡献为负的该字母的值。一个串的值就是把所有字母的贡献加起来。

例如,\(\texttt{DAAABDCA}\) 的值是 $ 1000 - 1 - 1 - 1 - 10 + 1000 + 100 + 1 = 2088 $。

现在,给定一个 Ranom Number,你可以把它的不超过一个的字符改为其它的 \(\texttt A \sim \texttt E\) 之间的字符,求你能得到的新 Ranom Number 的值最大可能是多少。

多组数据,输入串的总长度不超过 \(2 \times 10^5\)。

题目分析:

看到这个就特别想贪心,那么考虑如果选择了位置 \(p\) 那么是否存在一个位置显然比这个优呢。

如果我们要将字符变大,则显然就是想要让贡献不变的情况下产生的代价更小,也就是在相同的字符中的最靠左的一个,因为如果选择更靠右的,代价一定不会更小。

如果我们要将字符变小,同理应选择相同字符中最靠右的,因为即使我们将靠左的变小了,右边依然有同样大的,不会产生任何贡献。

所以能选择最多 \(10\) 个位置,就枚举一下就好了。

代码:

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e6+5;
const int INF = 1e17;
char s[N];
int n,val[10] = {1,10,100,1000,10000};
map<char,int> vis;
int get(){
int ans = 0;
char mx = 'A';
for(int i=n; i>=1; i--){
if(mx > s[i]) ans -= val[s[i]-'A'];
else ans += val[s[i]-'A'],mx = s[i];
}
return ans;
}
int solve(int pos){
char pre = s[pos];
int ans = -INF;
for(char i='A'; i<='E'; i++){
s[pos] = i;
ans = max(ans,get());
}
s[pos] = pre;
return ans;
}
signed main(){
int T;scanf("%lld",&T);
while(T--){
scanf("%s",s+1);
n = strlen(s+1);
int ans = -INF;
for(int i=1; i<=n; i++){
if(!vis[s[i]]){
vis[s[i]] = true;
ans = max(ans,solve(i));
}
}
vis.clear();
for(int i=n; i>=1; i--){
if(!vis[s[i]]){
vis[s[i]] = true;
ans = max(ans,solve(i));
}
}
printf("%lld\n",ans);
vis.clear();
}
return 0;
}

D.Pairs of Segments

题目描述:

给定 \(n\) 个线段 \([l_i, r_i]\),你需要从中删除尽可能少的线段,满足:

  • 剩余线段数量是偶数。
  • 剩余的线段可以两两配对,满足:
    • 属于同一对的两个线段有交;
    • 任意不属于同一对的两个线段均无交。

请你求出最少删除多少个线段才能满足要求。

多组数据,\(n\) 之和不超过 \(2000\),\(0 \leq l_i \leq r_i \leq 10^9\)。

题目分析:

删除一些线段肯定不如转化为选择线段好做。

显然考虑贪心,但是贪了一会发现其实贪心根本做不了,所以就考虑 \(dp\)。

看到这个数据范围支持 \(O(n^2)\) 的 \(dp\),所以就设 \(f[i]\) 表示考虑了前 \(i\) 个第 \(i\) 个必须匹配的最大匹配数量。

转移就是枚举前 \(i\) 个中与它相交的设为 \(j\),然后难道可以直接从 \(f[j-1]\) 转移吗?

发现其实不行啊,因为我们转移的位置必须满足它的右端点小于 \(i,j\) 的左端点,所以就考虑将所有的区间按右端点排序,因为这样能满足我们转移的位置一定在 \(i\) 之前被得到了。

那么直接离散化用树状数组维护一下以每个位置为右端点的最优答案直接询问区间最值然后转移就好了。

下面讲一下官解,感觉比较震撼。

考虑对于一对有交的线段我们记录下他们的并集,这样一个并集就代表了一对匹配,而两个并集不相交显然就是不属于同一对的线段无交,因此我们只需要在并集的集合里求一个最大不相交区间数就可以了。

这个问题就是个经典的问题,按右端点排序后直接贪心就好了,其实这种做法和 \(dp\) 本质相同。

代码:

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1e4+5;
struct node{
int l,r;
}a[N];
int tot,mx[N],b[N],f[N];
bool cmp(node a,node b){
return a.r < b.r;
}
int lowbit(int x){
return x & (-x);
}
void insert(int x,int val){
for(;x <= tot; x+=lowbit(x)){
mx[x] = max(mx[x],val);
}
}
int query(int x){
int ans = 0;
for(;x; x-=lowbit(x)){
ans = max(ans,mx[x]);
}
return ans;
}
int main(){
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
int T;scanf("%d",&T);
while(T--){
int n;scanf("%d",&n);
for(int i=1; i<=n; i++) scanf("%d%d",&a[i].l,&a[i].r),b[++tot] = a[i].l,b[++tot] = a[i].r;
sort(b+1,b+tot+1);tot = unique(b+1,b+tot+1) - b - 1;
for(int i=1; i<=n; i++){
a[i].l = lower_bound(b+1,b+tot+1,a[i].l) - b;
a[i].r = lower_bound(b+1,b+tot+1,a[i].r) - b;
}
sort(a+1,a+n+1,cmp);
for(int i=1; i<=n; i++){
for(int j=1; j<i; j++){
if(a[j].r >= a[i].l){
f[i] = max(f[i],query(min(a[j].l,a[i].l)-1) + 2);
}
}
insert(a[i].r,f[i]);
}
int ans = 0;
for(int i=1; i<=n; i++) ans = max(ans,f[i]);
printf("%d\n",n - ans);
for(int i=1; i<=tot; i++) mx[i] = 0;
for(int i=1; i<=n; i++) f[i] = 0;
}
return 0;
}

E.Fill the Matrix

题目描述:

有一个 \(n\) 行 \(n\) 列的矩阵,行和列都从 \(1\) 到 \(n\) 编号。对于第 \(i\) ,第 \(1 \sim a_i\) 个格子是黑色的,其余格子是白色的。

你可以把 \(1 \sim m\) 共 \(m\) 个整数放到矩阵里,满足两条规则:

  1. 每个格子包含至多一个整数。
  2. 黑色格子不能包含整数。

一个矩阵的美丽程度是满足这样的格子个数:该格子自身包含一个数 \(j\),且它右边与它相邻的格子包含的数为 \(j + 1\)。

请求出矩阵的最大美丽值。

多组数据,\(n\) 之和不超过 \(2 \times 10^5\),请注意 \(m\) 的大小可能超过 32 位整数所存储的范围。

题目分析:

考虑随便画一个图来理解这个局势是个什么样子:



考虑如果我们可以完全知道这个局面的所有信息那么美丽程度该怎么计算呢?

我们一定是每次选择一个长度最长的极长的白色格子段然后全部按顺序填数,直到能填的数不够了。

因为我们每多填一个区间这个区间最右边的这个数相当于浪费掉了,所以要尽可能少地浪费就是每次选尽可能长的区间。

但是上述做法就意味着我们必须知道 \(cnt[i]\) 表示长度为 \(i\) 的极长白色段的个数,而且 \(\sum cnt[i]\) 是 \(O(n^2)\) 的,所以如果直接暴力扫描线维护就直接炸了。

所以考虑尽可能减少多余的统计,也就是我们直接暴力维护每一个极长的白色段,然后找出它在什么位置会被断开,所以从当前位置到断开的位置它都是这么长,而断开之后就直接暴力维护断开之后的两个白色段就好了,从什么位置断开其实就是区间最大值的位置,需要注意的是如果有多个区间最大值我们也没必须要一次全部弄完因为这样复杂度就太高了,可以直接维护最靠左的区间最大值的位置,然后一个个去断就好了。

会发现这样复杂度就是很对的,因为对于每一个 \(a_i\) 只会导致一个极长的白色区间断开,而每次询问它的复杂度为 \(O(\log n)\) 所以总复杂度就是 \(O(n \log n)\)

代码:

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5+5;
const int INF = 1e18+5;
struct node{
int mx,pos;
}t[4 * N];
int cnt[N],a[N],n;
node operator + (node a,node b){
node c;
if(a.mx > b.mx) c = a;
else if(b.mx > a.mx) c = b;
else{
c.mx = a.mx;
c.pos = min(a.pos,b.pos);
}
return c;
}
void pushup(int now){
t[now] = t[now<<1] + t[now<<1|1];
}
node query(int now,int now_l,int now_r,int l,int r){
if(l <= now_l && now_r <= r) return t[now];
int mid = (now_l + now_r)>>1;
node ans = {-INF,INF};
if(l <= mid) ans = ans + query(now<<1,now_l,mid,l,r);
if(r > mid) ans = ans + query(now<<1|1,mid+1,now_r,l,r);
return ans;
}
void build(int now,int now_l,int now_r){
if(now_l == now_r){
t[now].mx = a[now_l];
t[now].pos = now_l;
return;
}
int mid = (now_l + now_r)>>1;
build(now<<1,now_l,mid);build(now<<1|1,mid+1,now_r);
pushup(now);
}
void solve(int l,int r,int pos){
if(l > r || pos <= 0) return;
node tmp = query(1,1,n,l,r);
cnt[r-l+1] += pos - a[tmp.pos];
solve(l,tmp.pos-1,a[tmp.pos]);
solve(tmp.pos+1,r,a[tmp.pos]);
}
signed main(){
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
int T;scanf("%lld",&T);
while(T--){
scanf("%lld",&n);
for(int i=1; i<=n; i++) scanf("%lld",&a[i]);
build(1,1,n);
solve(1,n,n);
int m;scanf("%lld",&m);
int ans = 0;
for(int i=n; i>=1; i--){
if(cnt[i] * i <= m){
m -= cnt[i] * i;
ans += cnt[i] * (i-1);
}
else{
ans += (m / i) * (i - 1);
m %= i;
ans += max(0ll,m - 1);
m = 0;
break;
}
}
printf("%lld\n",ans);
for(int i=1; i<=n; i++) cnt[i] = 0;
}
return 0;
}

F.Monocarp and a Strategic Game

题目描述:

Monocarp 玩一个策略游戏,在游戏中他开发了一个城市。这个城市有四种不同种族的生物——人类、精灵、兽人和矮人。

城市中的每个居民都有一个幸福值,它是一个整数,取决于城市中不同种族的生物数量。具体来说,每个居民的幸福值默认为 \(0\);对于同一个种族的每个其他生物,它会增加 \(1\);对于每个敌对种族的每个其他生物,它会减少 \(1\)。人类对于兽人有敌意(反之亦然),精灵对于矮人有敌意(反之亦然)。

游戏开始时,Monocarp 的城市没有居民。在游戏中,\(n\) 组生物会来到他的城市并希望在那里定居。第 \(i\) 组包含 \(a_{i}\) 个人类,\(b_{i}\) 个兽人,\(c_{i}\) 个精灵和 \(d_{i}\) 个矮人。每次,Monocarp 可以接受或拒绝将整个生物群体加入城市。

游戏根据以下公式计算 Monocarp 的得分:\(m+k\),其中 \(m\) 是城市中的居民数量,而 \(k\) 是城市中所有生物的幸福值之和。

帮助 Monocarp 通过最大化得分来获得游戏的胜利!

\(n \le 3·10^5,0 \le a_i,b_i,c_i,d_i \le 10^9\)

题目分析:

动态维护这个贡献大概是没啥想法,考虑如果现在四个种族的数量分别为 \(A,B,C,D\) (AB敌对,CD敌对)那么幸福值是多少:

\[A + B + C + D + A(A-1) - AB + B(B-1) - AB + C(C-1) - CD + D(D-1) - CD
\]

化简一下就是:

\[(A-B)^2 + (C-D)^2
\]

考虑令一个群体为一个向量 \((a_i-b_i,c_i-d_i)\),那么幸福值之和就是对应的向量加和的模长的平方。

考虑闵可夫斯基和,也就是每一个向量围绕着凸包转一圈形成新的凸包,最优答案一定就是这个凸包上的某一个点。

所以直接做就好了。

【题解】Educational Codeforces Round 150(CF1841)的更多相关文章

  1. Educational Codeforces Round 63 (Rated for Div. 2) 题解

    Educational Codeforces Round 63 (Rated for Div. 2)题解 题目链接 A. Reverse a Substring 给出一个字符串,现在可以对这个字符串进 ...

  2. Educational Codeforces Round 48 (Rated for Div. 2) CD题解

    Educational Codeforces Round 48 (Rated for Div. 2) C. Vasya And The Mushrooms 题目链接:https://codeforce ...

  3. Educational Codeforces Round 60 (Rated for Div. 2) 题解

    Educational Codeforces Round 60 (Rated for Div. 2) 题目链接:https://codeforces.com/contest/1117 A. Best ...

  4. Educational Codeforces Round 59 (Rated for Div. 2) DE题解

    Educational Codeforces Round 59 (Rated for Div. 2) D. Compression 题目链接:https://codeforces.com/contes ...

  5. Educational Codeforces Round 58 (Rated for Div. 2) 题解

    Educational Codeforces Round 58 (Rated for Div. 2)  题目总链接:https://codeforces.com/contest/1101 A. Min ...

  6. Educational Codeforces Round 65 (Rated for Div. 2)题解

    Educational Codeforces Round 65 (Rated for Div. 2)题解 题目链接 A. Telephone Number 水题,代码如下: Code #include ...

  7. Educational Codeforces Round 64 (Rated for Div. 2)题解

    Educational Codeforces Round 64 (Rated for Div. 2)题解 题目链接 A. Inscribed Figures 水题,但是坑了很多人.需要注意以下就是正方 ...

  8. Educational Codeforces Round 64 部分题解

    Educational Codeforces Round 64 部分题解 不更了不更了 CF1156D 0-1-Tree 有一棵树,边权都是0或1.定义点对\(x,y(x\neq y)\)合法当且仅当 ...

  9. Educational Codeforces Round 64部分题解

    Educational Codeforces Round 64部分题解 A 题目大意:给定三角形(高等于低的等腰),正方形,圆,在满足其高,边长,半径最大(保证在上一个图形的内部)的前提下. 判断交点 ...

  10. Educational Codeforces Round 53 (Rated for Div. 2) (前五题题解)

    这场比赛没有打,后来补了一下,第五题数位dp好不容易才搞出来(我太菜啊). 比赛传送门:http://codeforces.com/contest/1073 A. Diverse Substring ...

随机推荐

  1. JVM有意思的图-持续更新

    放一些JVM有意思的图 通过一行代码联想JVM:

  2. [OpenCV-Python] 17 形态学转换

    文章目录 OpenCV-Python:IV OpenCV中的图像处理 17 形态学转换 17.1 腐蚀 17.2 膨胀 17.3 开运算 17.4 闭运算 17.5 形态学梯度 17.6 礼帽 17. ...

  3. PaddlePaddle 飞桨复现 ResNeXt

    import paddle.nn as nn import paddle class BN_Conv2D(nn.Layer): """ BN_CONV_RELU &quo ...

  4. 把ChatGPT调教成机器学习专家,以逻辑回归模型的学习为例

    大家好我是章北海mlpy 看到一个蛮有意思的项目,可以把ChatGPT调教成导师 https://github.com/JushBJJ/Mr.-Ranedeer-AI-Tutor 可以根据你选择的学习 ...

  5. 解决v-html渲染HTML标签展示信息有误问题

    后端返回的数据内容为: // html反转义 HTMLDecode(text) { var reg = /<[^>]+>/g; if (reg.test(text)) { retur ...

  6. express服务器框架

    Express 为了提高开发效率,我们在开发过程中,都会尽量使用别人已经开发好的第三方模块,而我们想要快速实现服务器端的开发,推荐一个当下比较流行的框架:Express Express 作为开发框架, ...

  7. 2022-12-28:有n个黑白棋子,它们的一面是黑色,一面是白色, 它们被排成一行,位置0~n-1上。一开始所有的棋子都是黑色向上, 一共有q次操作,每次操作将位置标号在区间[L,R]内的所有棋子翻

    2022-12-28:有n个黑白棋子,它们的一面是黑色,一面是白色, 它们被排成一行,位置0~n-1上.一开始所有的棋子都是黑色向上, 一共有q次操作,每次操作将位置标号在区间[L,R]内的所有棋子翻 ...

  8. 2020-01-16:我截获了登录token的话,是不是就获得了登录状态,这样就不安全了。如何保证安全?

    福哥答案2020-01-06:[知乎答案:](https://www.zhihu.com/question/439602796)首先,Token 一般放在 Header 或者 Cookies 中,Ht ...

  9. 2021-09-27:Pow(x, n)。实现 pow(x, n) ,即计算 x 的 n 次幂函数(即,x**n)。力扣50。

    2021-09-27:Pow(x, n).实现 pow(x, n) ,即计算 x 的 n 次幂函数(即,x**n).力扣50. 福大大 答案2021-09-27: 遍历n的二进制位. 时间复杂度:O( ...

  10. 鼠标移入select options会触发mouseleave 事件处理方案

    近来遇到一项目有一侧边工具菜单,在鼠标mouseenter事件打开对应的详细操作列表,当mouseleave时进行关闭,然操作列表中有一个select , 每当鼠标移入select options 时 ...