Codeforces Round 968 (Div. 2)(A,B,C,D1,D2)

2024-08-31 00:28
文章标签 codeforces round 968 div d1 d2

本文主要是介绍Codeforces Round 968 (Div. 2)(A,B,C,D1,D2),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

比赛链接

这场还是有点东西的,这几个题都不难,但是要做对还是比较麻烦的。B是一个简单的博弈,C是鸽巢原理,D1是推一个结论,D2是一个dp,初始化比较烦人。


A. Turtle and Good Strings

题面:

乌龟认为,如果存在一串字符串 t 1 , t 2 , … , t k t_1, t_2, \ldots, t_k t1,t2,,tk k k k 是任意整数),那么字符串 s s s 就是一个好字符串:

  • k ≥ 2 k \ge 2 k2 .
  • s = t 1 + t 2 + … + t k s = t_1 + t_2 + \ldots + t_k s=t1+t2++tk ,其中 + + + 表示连接操作。例如, abc = a + bc \texttt{abc} = \texttt{a} + \texttt{bc} abc=a+bc
  • 对于所有 1 ≤ i < j ≤ k 1 \le i \lt j \le k 1i<jk t i t_i ti 的第一个字符不等于 1 ≤ i < j ≤ k 1 \le i \lt j \le k 1i<jk不等于 t j t_j tj 的最后一个字符。

乌龟得到一个由小写拉丁字母组成的字符串 s s s 。请告诉他 s s s 是否是一个好字符串!

思路:

其实发现如果拆的字符串多的话,比较的字符就会更多,更不容易满足条件,所以我们就拆成两个就可以了。

而且无论中间怎么拆,第一个字符串的第一个字符一定会和最后一个字符串的最后一个字符进行比较,其他的不比较,所以我们只需要第一个字符串的第一个字符和最后一个字符串的最后一个字符比较一下就可以了。

code:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;int T,n;
string s;int main(){cin>>T;while(T--){cin>>n>>s;if(s[0]==s[n-1])puts("NO");else puts("YES");}return 0;
}

B. Turtle and Piggy Are Playing a Game 2

题面:

小乌龟和小猪在玩一个数列游戏。他们得到一个数列 a 1 , a 2 , … , a n a_1, a_2, \ldots, a_n a1,a2,,an ,小乌龟先来。小乌龟和小猪轮流进行(所以,小乌龟做第一轮,小猪做第二轮,小乌龟做第三轮,等等)。

游戏过程如下

  • 假设当前序列的长度为 m m m 。如果是 m = 1 m = 1 m=1 ,游戏结束。
  • 如果游戏没有结束,轮到小乌龟,那么小乌龟必须选择一个整数 i i i ,使得 1 ≤ i ≤ m − 1 1 \le i \le m - 1 1im1 ,将 a i a_i ai 设置为 max ⁡ ( a i , a i + 1 ) \max(a_i, a_{i + 1}) max(ai,ai+1) ,并删除 a i + 1 a_{i + 1} ai+1
  • 如果游戏没有结束,轮到小猪,那么小猪必须选择一个整数 i i i ,使得 1 ≤ i ≤ m − 1 1 \le i \le m - 1 1im1 ,将 a i a_i ai 设置为 min ⁡ ( a i , a i + 1 ) \min(a_i, a_{i + 1}) min(ai,ai+1) ,并删除 a i + 1 a_{i + 1} ai+1

小乌龟希望最后最大化 a 1 a_1 a1 的值,而小猪希望最后最小化 a 1 a_1 a1 的值。如果双方都以最优方式下棋,求最后 a 1 a_1 a1 的值。

思路:

这种放在 B B B 的位置上的题一般出不到什么牛逼高大上的博弈模型,或者是SG函数,所以我们就以最简单的博弈思想来看就行了:要么自己养出最大最小值,要么阻止对方得到最小最大值。

我们随便挑选一个人的视角,比如我们代入小乌龟的视角,想要最大化最后的值,那么我们有两个策略:

  1. 每次删掉最大值旁边的数,保留最小值
  2. 删掉最小值,让对方得不到最小值。

其实我们发现第一个策略是不可行的,因为对方只要采取第二种策略,我们留着的最大值就消失了,所以这个博弈其实就是让两个人互相删掉对方的最大最小值,最后剩下的其实就是中值。

code:

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn=1e5+5;int T,n,a[maxn];int main(){cin>>T;while(T--){cin>>n;for(int i=1;i<=n;i++)cin>>a[i];sort(a+1,a+n+1);cout<<a[n/2+1]<<"\n";}return 0;
}

C. Turtle and Good Pairs

题面:

乌龟会给出一个由小写拉丁字母组成的字符串 s s s

乌龟认为一对整数 ( i , j ) (i, j) (i,j) ( 1 ≤ i < j ≤ n 1 \le i < j \le n 1i<jn ) 是令人愉快的一对,当且仅当存在一个整数 k k k ,使得 i ≤ k < j i \le k < j ik<j 和下面两个条件都成立:

  • s k ≠ s k + 1 s_k \ne s_{k + 1} sk=sk+1 ;
  • s k ≠ s i s_k \ne s_i sk=si s k + 1 ≠ s j s_{k + 1} \ne s_j sk+1=sj

此外,乌龟认为一对整数 ( i , j ) (i, j) (i,j) ( 1 ≤ i < j ≤ n 1 \le i < j \le n 1i<jn )是一对好数,当且仅当 s i = s j s_i = s_j si=sj ( i , j ) (i, j) (i,j) 是一对令人愉快的数。

乌龟想给字符串 s s s 重新排序,以便使好的配对数最大。请帮帮他!

思路:

鸽巢原理好题。

这题其实看明白的话,其实就是在说像是aaabb这种,前面一部分都是一个字符,后面一部分都是另一个字符的子串不算数。所以我们尽可能把相同的字符隔开,变成像是ababa这种形式就好了。

我们把奇数位置看成鸽巢,把字符看成鸽子,其实就是往鸽巢里塞鸽子(塞满奇数位置剩下的依次放入偶数位置即可),这就是一个鸽巢原理。

所以我们把所有字符和它们出现的次数处理出来,按照出现次数排序。然后将字符一个一个依次放入奇数位置和偶数位置即可。

code:

#include <iostream>
#include <cstdio>
#include <map>
#include <cstring>
using namespace std;int T,n;
string s;int main(){cin>>T;while(T--){cin>>n>>s;map<char,int> mp;multimap<int,char> rmp;for(int i=0;i<n;i++)mp[s[i]]++;for(auto [ch,cnt]:mp)rmp.insert(pair<int,char>(cnt,ch));for(int i=0;i<n;i+=2){char ch=rmp.begin()->second;
//			cout<<ch<<" "<<mp.size()<<" "<<rmp.size()<<endl;s[i]=ch;mp[ch]--;if(mp[ch]==0){mp.erase(ch);rmp.erase(rmp.begin());}}for(int i=1;i<n;i+=2){char ch=rmp.begin()->second;s[i]=ch;mp[ch]--;if(mp[ch]==0){mp.erase(ch);rmp.erase(rmp.begin());}}cout<<s<<endl;}return 0;
}

D1. Turtle and a MEX Problem (Easy Version)

题面:

两个版本是不同的问题。在这个版本的问题中,你可以两次或多次选择同一个整数。只有两个版本的问题都解决了,你才能进行破解。

有一天,乌龟在玩 n n n 个序列。假设第 i i i 个序列的长度为 l i l_i li 。那么第 i i i 个序列是 a i , 1 , a i , 2 , … , a i , l i a_{i, 1}, a_{i, 2}, \ldots, a_{i, l_i} ai,1,ai,2,,ai,li .

小猪在乌龟玩耍的时候给乌龟出了一道难题。问题的陈述是

  • 一开始有一个非负整数 x x x 。小乌龟要对这个整数进行任意次数(可能是零)的运算。
  • 在每次运算中,乌龟可以选择一个整数 i i i ,使得 1 ≤ i ≤ n 1 \le i \le n 1in ,并将 x x x 设为 mex † ( x , a i , 1 , a i , 2 , … , a i , l i ) \text{mex}^{\dagger}(x, a_{i, 1}, a_{i, 2}, \ldots, a_{i, l_i}) mex(x,ai,1,ai,2,,ai,li)
  • 乌龟被要求找出答案,即进行任意次数运算后 x x x最大值。

乌龟毫不费力地解决了上述问题。他将 f ( k ) f(k) f(k) 定义为当 x x x 的初始值为 k k k 时上述问题的答案。

然后,小猪给了乌龟一个非负整数 m m m ,让乌龟找出 ∑ i = 0 m f ( i ) \sum\limits_{i=0}^m f(i) i=0mf(i) 的值(即 f ( 0 ) + f ( 1 ) + … + f ( m ) f(0) + f(1) + \ldots + f(m) f(0)+f(1)++f(m) 的值)。不幸的是,他无法解决这个问题。请帮帮他!

† mex ( c 1 , c 2 , … , c k ) ^{\dagger}\text{mex}(c_1, c_2, \ldots, c_k) mex(c1,c2,,ck) 被定义为在序列 c c c 中不出现的最小非负整数 x x x 。例如, mex ( 2 , 2 , 0 , 3 ) \text{mex}(2, 2, 0, 3) mex(2,2,0,3) 1 1 1 mex ( 1 , 2 ) \text{mex}(1, 2) mex(1,2) 0 0 0

思路:

不难发现一个性质,假设一个序列最小未出现的非负整数为 m e x 1 mex1 mex1,第二小未出现的非负整数为 m e x 2 mex2 mex2,那么只要这个数不是 m e x 1 mex1 mex1,做一次运算的结果就是 m e x 1 mex1 mex1,做两次运算的结果就是 m e x 2 mex2 mex2。每个序列最大能 m e x mex mex 到的只能是到 m e x 2 mex2 mex2

所以我们只需要找到所有序列最大的 m e x 2 mex2 mex2,让小于 m e x 2 mex2 mex2 的数都变成 m e x 2 mex2 mex2,这样 f ( 0 ) + f ( 1 ) + … + f ( m ) = m e x 2 + m e x 2 + ⋯ + m e x 2 + ( m e x 2 + 1 ) + ( m e x 2 + 2 ) + ⋯ + m = ( m e x 2 + 1 ) ∗ m e x 2 + ( m + m e x 2 + 1 ) ∗ ( m − m e x 2 ) / 2 f(0) + f(1) + \ldots + f(m)=mex2+mex2+\dots+mex2+(mex2+1)+(mex2+2)+\dots+m=(mex2+1)*mex2+(m+mex2+1)*(m-mex2)/2 f(0)+f(1)++f(m)=mex2+mex2++mex2+(mex2+1)+(mex2+2)++m=(mex2+1)mex2+(m+mex2+1)(mmex2)/2 就是最大的。

code:

#include <iostream>
#include <cstdio>
#include <set>
using namespace std;
typedef long long ll;int T,n,m,mx; int main(){cin>>T;while(T--){cin>>n>>m;mx=0;for(int i=1,l;i<=n;i++){cin>>l;set<int> S;bool f=false;for(int j=1,t;j<=l;j++){cin>>t;S.insert(t);}for(int j=0;;j++){if(S.find(j)==S.end())if(!f)f=true;else {mx=max(mx,j);break;}}}ll ans=0;if(mx<m)ans=1ll*(mx+1)*mx+1ll*(m-mx)*(m+mx+1)/2;else ans=1ll*mx*(m+1);cout<<ans<<endl;}return 0;
}

D2. Turtle and a MEX Problem (Hard Version)

题面:

两个版本是不同的问题。在这个版本的问题中,你不能两次或多次选择同一个整数。只有两个版本的问题都解决了,你才能进行破解。

有一天,乌龟在玩 n n n 序列。假设第 i i i 个序列的长度为 l i l_i li 。那么第 i i i 个序列是 a i , 1 , a i , 2 , … , a i , l i a_{i, 1}, a_{i, 2}, \ldots, a_{i, l_i} ai,1,ai,2,,ai,li .

小猪在乌龟玩耍的时候给乌龟出了一道难题。问题的陈述是

  • 一开始有一个非负整数 x x x 。小乌龟要对这个整数进行任意次数(可能是零)的运算。
  • 在每一次运算中,乌龟可以选择 i i i 这样一个整数,即 1 ≤ i ≤ n 1 \le i \le n 1in i i i 之前没有被选择,并将 x x x 设置为 mex † ( x , a i , 1 , a i , 2 , … , a i , l i ) \text{mex}^{\dagger}(x, a_{i, 1}, a_{i, 2}, \ldots, a_{i, l_i}) mex(x,ai,1,ai,2,,ai,li)
  • 乌龟被要求找出答案,即进行任意次数运算后 x x x最大值。

乌龟毫不费力地解决了上述问题。他将 f ( k ) f(k) f(k) 定义为当 x x x 的初始值为 k k k 时上述问题的答案。

然后,小猪给了乌龟一个非负整数 m m m ,让乌龟找出 ∑ i = 0 m f ( i ) \sum\limits_{i=0}^m f(i) i=0mf(i) 的值(即 f ( 0 ) + f ( 1 ) + … + f ( m ) f(0) + f(1) + \ldots + f(m) f(0)+f(1)++f(m) 的值)。不幸的是,他无法解决这个问题。请帮帮他!

† mex ( c 1 , c 2 , … , c k ) ^{\dagger}\text{mex}(c_1, c_2, \ldots, c_k) mex(c1,c2,,ck) 定义为序列 c c c 中不出现的最小非负整数 x x x 。例如, mex ( 2 , 2 , 0 , 3 ) \text{mex}(2, 2, 0, 3) mex(2,2,0,3) 1 1 1 mex ( 1 , 2 ) \text{mex}(1, 2) mex(1,2) 0 0 0

思路:

其实不难,但是赛时被前三个题整麻了,就不觉得这个能做上来,结果这个题就赛时坠机了,差一点写出来。

这个题和上一个的区别在于不能对一个序列进行多次 m e x mex mex 运算,只能做一次。还是假设一个序列最小未出现的非负整数为 m e x 1 mex1 mex1,第二小未出现的非负整数为 m e x 2 mex2 mex2。所以对一个序列,我们做一次 m e x mex mex,只要这个数不是一开始就是 m e x 1 mex1 mex1,就会得到 m e x 1 mex1 mex1

但是如果这个数一开始就是 m e x 1 mex1 mex1,这时可以得到 m e x 2 mex2 mex2。或者是有另一个序列的最小未出现的非负整数也是这个 m e x 1 mex1 mex1,那么无论什么数都可以得到 m e x 2 mex2 mex2。其实可以发现一个数变成另一个数的方法就这两种。

我们用一条有向边 m e x 1 → m e x 2 mex1\rightarrow mex2 mex1mex2 表示原本为 m e x 1 mex1 mex1 的数可以直接得到 m e x 2 mex2 mex2。再用一个 m x mx mx 表示所有数都可以变成的最大的 m e x 2 mex2 mex2。那么对一个数,要么不变,要么变成有向边连向的数,要么变成 m x mx mx

可以发现 m e x 2 mex2 mex2 的大小是随着序列长度变化的,它最大就是 l + 1 l+1 l+1,而 ∑ l ≤ 2 × 1 0 5 \sum l\le 2\times 10^5 l2×105,所以 m e x 1 → m e x 2 mex1\rightarrow mex2 mex1mex2 以及 m e x 2 mex2 mex2 最大也就到 2 × 1 0 5 2\times 10^5 2×105。我们可以用 t o to to 数组表示每个数可以变成的最大的数, t o to to 数组有可能发生变化的也只有前 m e x 2 mex2 mex2 的部分。我们处理这部分的 t o to to 数组不会超时。高出的部分直接等差数列求和即可。

code:

#include <iostream>
#include <cstdio>
#include <set>
#include <vector>
#include <queue>
using namespace std;
typedef long long ll;
const int maxn=2e5+5;
typedef pair<int,int> pii;int T,n,m;int top;
pii ttt[maxn];int M;
vector<int> head,d,to;
int ent;
struct edge{int v,nxt;
}e[maxn];
void add(int u,int v){e[++ent]={v,head[u]};head[u]=ent;
}signed main(){cin>>T;while(T--){cin>>n>>m;ent=M=top=0;for(int i=1,l;i<=n;i++){cin>>l;set<int> S;int k1=-1,k2;for(int i=1,t;i<=l;i++){cin>>t;S.insert(t);}for(int j=0;;j++){if(S.find(j)==S.end()){if(!~k1)k1=j;else {k2=j;break;}}}M=max(M,k2);ttt[++top]=pii(k1,k2);}head.resize(M+1);d.resize(M+1);to.resize(M+1);for(int i=0;i<=M;i++)head[i]=d[i]=to[i]=0;for(int i=1;i<=top;i++){int k1=ttt[i].first,k2=ttt[i].second;d[k1]++;add(k1,k2); }for(int u=M;u>=0;u--){to[u]=u;for(int i=head[u],v;i;i=e[i].nxt){v=e[i].v;to[u]=max(to[u],to[v]);}}int mx=0;for(int i=0;i<=M;i++)if(d[i]>1)mx=max(mx,to[i]);else if(d[i]==1)mx=max(mx,i);ll ans=0;for(int i=0;i<=min(M,m);i++){ans+=max(to[i],mx);}if(m>M)ans+=1ll*(m+M+1)*(m-M)/2;cout<<ans<<endl;}return 0;
}

这篇关于Codeforces Round 968 (Div. 2)(A,B,C,D1,D2)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1122363

相关文章

Codeforces Round #240 (Div. 2) E分治算法探究1

Codeforces Round #240 (Div. 2) E  http://codeforces.com/contest/415/problem/E 2^n个数,每次操作将其分成2^q份,对于每一份内部的数进行翻转(逆序),每次操作完后输出操作后新序列的逆序对数。 图一:  划分子问题。 图二: 分而治之,=>  合并 。 图三: 回溯:

Codeforces Round #261 (Div. 2)小记

A  XX注意最后输出满足条件,我也不知道为什么写的这么长。 #define X first#define Y secondvector<pair<int , int> > a ;int can(pair<int , int> c){return -1000 <= c.X && c.X <= 1000&& -1000 <= c.Y && c.Y <= 1000 ;}int m

Codeforces Beta Round #47 C凸包 (最终写法)

题意慢慢看。 typedef long long LL ;int cmp(double x){if(fabs(x) < 1e-8) return 0 ;return x > 0 ? 1 : -1 ;}struct point{double x , y ;point(){}point(double _x , double _y):x(_x) , y(_y){}point op

Codeforces Round #113 (Div. 2) B 判断多边形是否在凸包内

题目点击打开链接 凸多边形A, 多边形B, 判断B是否严格在A内。  注意AB有重点 。  将A,B上的点合在一起求凸包,如果凸包上的点是B的某个点,则B肯定不在A内。 或者说B上的某点在凸包的边上则也说明B不严格在A里面。 这个处理有个巧妙的方法,只需在求凸包的时候, <=  改成< 也就是说凸包一条边上的所有点都重复点都记录在凸包里面了。 另外不能去重点。 int

Codeforces 482B 线段树

求是否存在这样的n个数; m次操作,每次操作就是三个数 l ,r,val          a[l] & a[l+1] &......&a[r] = val 就是区间l---r上的与的值为val 。 也就是意味着区间[L , R] 每个数要执行 | val 操作  最后判断  a[l] & a[l+1] &......&a[r] 是否= val import ja

CSS实现DIV三角形

本文内容收集来自网络 #triangle-up {width: 0;height: 0;border-left: 50px solid transparent;border-right: 50px solid transparent;border-bottom: 100px solid red;} #triangle-down {width: 0;height: 0;bor

创建一个大的DIV,里面的包含两个DIV是可以自由移动

创建一个大的DIV,里面的包含两个DIV是可以自由移动 <body>         <div style="position: relative; background:#DDF8CF;line-height: 50px"> <div style="text-align: center; width: 100%;padding-top: 0px;"><h3>定&nbsp;位&nbsp;

Codeforces Round 971 (Div. 4) (A~G1)

A、B题太简单,不做解释 C 对于 x y 两个方向,每一个方向至少需要 x / k 向上取整的步数,取最大值。 由于 x 方向先移动,假如 x 方向需要的步数多于 y 方向的步数,那么最后 y 方向的那一步就不需要了,答案减 1 代码 #include <iostream>#include <algorithm>#include <vector>#include <string>

CF#271 (Div. 2) D.(dp)

D. Flowers time limit per test 1.5 seconds memory limit per test 256 megabytes input standard input output standard output 题目链接: http://codeforces.com/contest/474/problem/D We s

CF #278 (Div. 2) B.(暴力枚举+推导公式+数学构造)

B. Candy Boxes time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output 题目链接: http://codeforces.com/contest/488/problem/B There