2020-02-03 22:27阅读: 194评论: 0推荐: 0

Codeforces Round #616 (Div. 2)

A. Even But Not Even (CF 1291 A)

题目大意

给定一个数,要求删去其中的一些数字后所得的数是奇数但各位数的和为偶数。

解题思路

保留两位奇数即可,其中一个奇数在末位。

神奇的代码
#include <bits/stdc++.h>
#define MIN(a,b) ((((a)<(b)?(a):(b))))
#define MAX(a,b) ((((a)>(b)?(a):(b))))
#define ABS(a) ((((a)>0?(a):-(a))))
using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector<PII> VPII;
typedef vector<LL> VL;
typedef pair<LL,LL> PLL;
typedef vector<PLL> VPLL;
template <typename T>
void read(T &x) {
int s = 0, c = getchar();
x = 0;
while (isspace(c)) c = getchar();
if (c == 45) s = 1, c = getchar();
while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
if (s) x = -x;
}
template <typename T>
void write(T x, char c = ' ') {
int b[40], l = 0;
if (x < 0) putchar(45), x = -x;
while (x > 0) b[l++] = x % 10, x /= 10;
if (!l) putchar(48);
while (l) putchar(b[--l] | 48);
putchar(c);
}
int main(void) {
int kase; read(kase);
for (int i = 1; i <= kase; i++) {
int n;
char s[3006]={0};
read(n);
scanf("%s",s);
int fir=-1,sec=-1;
for(int i=0;i<n;++i)
if ((s[i]-'0')&1)
if (fir==-1) fir=i;
else if (sec==-1) sec=i;
else break;
if (sec==-1) puts("-1");
else s[sec+1]=0,printf("%s\n",s);
}
return 0;
}


B. Array Sharpening (CF 1291 B)

题目大意

给定一个有n个数的数字序列a,可以对序列里的任意正数多次减一,要求将序列变成先严格递增后严格递减,也可以单增或单减,问能否做到。

解题思路

我们让波峰尽可能靠右,波峰左边的就看它是否a[i]ii0开始),第一个不满足该不等式的位置当做波峰,波峰的右边包括波峰看其是否满足a[i]ni1(i>k),都满足则可,否则不可。因为我们让波峰尽可能靠右,这样对于波峰右边的数所需要满足的条件就不会那么苛刻。

神奇的代码
#include <bits/stdc++.h>
#define MIN(a,b) ((((a)<(b)?(a):(b))))
#define MAX(a,b) ((((a)>(b)?(a):(b))))
#define ABS(a) ((((a)>0?(a):-(a))))
using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector<PII> VPII;
typedef vector<LL> VL;
typedef pair<LL,LL> PLL;
typedef vector<PLL> VPLL;
template <typename T>
void read(T &x) {
int s = 0, c = getchar();
x = 0;
while (isspace(c)) c = getchar();
if (c == 45) s = 1, c = getchar();
while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
if (s) x = -x;
}
template <typename T>
void write(T x, char c = ' ') {
int b[40], l = 0;
if (x < 0) putchar(45), x = -x;
while (x > 0) b[l++] = x % 10, x /= 10;
if (!l) putchar(48);
while (l) putchar(b[--l] | 48);
putchar(c);
}
bool solve(int n,int a[]){
int qwq=0;
while(qwq<n&&a[qwq]>=qwq) ++qwq;
if (qwq==n) return true;
--qwq;
while(qwq<n&&a[qwq]>=n-qwq-1) ++qwq;
if (qwq==n) return true;
return false;
}
int main(void) {
int kase; read(kase);
for (int i = 1; i <= kase; i++) {
int n;
read(n);
int a[n];
for(int i=0;i<n;++i) read(a[i]);
if (solve(n,a)) puts("Yes");
else puts("No");
}
return 0;
}


C. Mind Control (CF 1291 C)

题目大意

给定n个数,有n个人,你第m次拿,对于每个人来说,他们可以拿第一个数或最后一个数,现在在取数开始前,你可以指定最多k个人,当他们拿的时候规定他们分别是拿第一个数还是最后一个数。而没有被你指定的人,当他们取的时候,他们有可能拿第一个数也可能拿最后一个数。现在需要你指定最多k个人,来使得不管其他人怎么取,到你取的时候,你取到的数始终大于等于x,且这个x尽可能大。

解题思路

m1个人取后,剩下的是连续的nm+1个数。如果k=0的话,那么到我取的时候情况数就有m种,而答案就是这m种情况中第一个和最后一个数的最大值的最小值。我们考虑如果指定了一个人的话,对最终的情况数会有什么影响。
我们把这个取数过程的状态树画出来,会有m层,进而能发现,如果对其中任意一个人进行指定,那么最边边上的状态就会取不到了,最终的情况数就只有m1种,而这m1种就有两种可能。如果指定k个人,那么最终的情况数就只有mk种,且这mk种情况在状态树中是连续的。
状态树
那么我们先把所有最终情况求出来,即qwq[i]=max(a[i],a[i+nm]),然后我们取连续的mk个数求最小值,答案就是这些最小值中的最大值。
O(n2)暴力,O(nlog2n)线段树或ST表,O(n)单调队列都可以。

神奇的代码
#include <bits/stdc++.h>
#define MIN(a,b) ((((a)<(b)?(a):(b))))
#define MAX(a,b) ((((a)>(b)?(a):(b))))
#define ABS(a) ((((a)>0?(a):-(a))))
using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector<PII> VPII;
typedef vector<LL> VL;
typedef pair<LL,LL> PLL;
typedef vector<PLL> VPLL;
template <typename T>
void read(T &x) {
int s = 0, c = getchar();
x = 0;
while (isspace(c)) c = getchar();
if (c == 45) s = 1, c = getchar();
while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
if (s) x = -x;
}
template <typename T>
void write(T x, char c = ' ') {
int b[40], l = 0;
if (x < 0) putchar(45), x = -x;
while (x > 0) b[l++] = x % 10, x /= 10;
if (!l) putchar(48);
while (l) putchar(b[--l] | 48);
putchar(c);
}
int main(void) {
int kase; read(kase);
for (int ii = 1; ii <= kase; ii++) {
int n,m,k;
read(n);
read(m);
read(k);
k=min(k,m-1);
int a[n+1];
for(int i=1;i<=n;++i) read(a[i]);
int len=n-m;
deque<pair<int,int>> team;
int ans=0;
for(int i=1;i<=m;++i){
int qwq=max(a[i],a[i+len]);
while(!team.empty()&&team.front().second<i-m+k+1) team.pop_front();
while(!team.empty()&&team.back().first>=qwq) team.pop_back();
team.push_back(make_pair(qwq,i));
if (i>m-k-1) ans=max(ans,team.front().first);
}
write(ans,'\n');
}
return 0;
}


D. Irreducible Anagrams (CF 1291 D)

题目大意

给定一个串s,有q次询问,每次询问给定两个正整数l,r,问子串s[l...r]是否有一个不可约的同构串。两个串s,t互为同构串就是说s可以通过重新排列串s字母使得变为t。若存在一个串ts的一个同构串,ts,且s可以分为k>1个子串s1,s2,...,skt也相应位置分为k>1个子串t1,t2,...,tk,每个对应的子串si,ti都是同构串,则t串是可约的,否则是不可约的。

解题思路

我们考虑一下一个串是否是可约的。
首先长度为一的串是不可约的,因为它无法分割成两部分或以上,前提为假命题为真。
然后一个串中只含有一个字母的也是不可约的,因为它的同构串只有它本身。
然后我们从字母出现的位置顺序考虑。如果一个s的同构串t是不可约的,那就意味着我无法将s分成两部分或以上,否则存在一个子串使得siti不同构。换句话说,就是我在取t的前k位时,这前k位中出现的字母在s中出现的最远位置要大于k,这才使得我要增大k,才有可能使得t串的第一部分与s串的第一部分同构,而无法做到这一点就意味着我取了前m位时,这其中出现的字母在s中的最远距离已经是s的尾端,这就要我们把s取完,才使得s的第一部分与t的第一部分同构,而此时没有第二部分了,那么此时t就是个不可约的同构串。
从上面的思路我们就将问题转换成,这里有从左到右标号分别为1nn个格子,以及我们有m组数(m个字母),每组数里有若干个从小到大排好的数1an且各不相同(该字母出现的位置),共有n个数。现在要把这n个数放到n个格子里,对于一组数来说要先放小的数才能放大的数。问能否有一种放法,使得最大的数不在最后一个格子,且对于最大的数所在格子的前面每个格子x,里面放的数满足max1ix(numi)>x
最大的数所在的那一组中,如果最小的数不是1,那么就一定存在该种放法,即我们直接把最大的数所在的那组数都放到前面的格子里即可。也就是说s[l]!=s[r]时,就存在不可约的同构串。
而如果最小的数是1,如果有两组的话,可以发现我们无法满足上述的条件,而如果有三组及以上,都可以满足。

神奇的代码
#include <bits/stdc++.h>
#define MIN(a,b) ((((a)<(b)?(a):(b))))
#define MAX(a,b) ((((a)>(b)?(a):(b))))
#define ABS(a) ((((a)>0?(a):-(a))))
using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector<PII> VPII;
typedef vector<LL> VL;
typedef pair<LL,LL> PLL;
typedef vector<PLL> VPLL;
template <typename T>
void read(T &x) {
int s = 0, c = getchar();
x = 0;
while (isspace(c)) c = getchar();
if (c == 45) s = 1, c = getchar();
while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
if (s) x = -x;
}
template <typename T>
void write(T x, char c = ' ') {
int b[40], l = 0;
if (x < 0) putchar(45), x = -x;
while (x > 0) b[l++] = x % 10, x /= 10;
if (!l) putchar(48);
while (l) putchar(b[--l] | 48);
putchar(c);
}
bool check(int pos[][26],int l,int r){
int cnt=0;
for(int i=0;i<26;++i)
cnt+=(pos[r][i]-pos[l-1][i])>0;
return cnt>2;
}
int main(void) {
char s[200006];
scanf("%s",s+1);
int n=strlen(s+1);
int pos[n+1][26]={0};
for(int i=1;i<=n;++i){
pos[i][s[i]-'a']++;
for(int j=0;j<26;++j)
pos[i][j]+=pos[i-1][j];
}
int q;
read(q);
for(int l,r,i=1;i<=q;++i){
read(l);
read(r);
if (l==r) puts("Yes");
else if (s[l]!=s[r]) puts("Yes");
else if (check(pos,l,r)) puts("Yes");
else puts("No");
}
return 0;
}


本文作者:~Lanly~

本文链接:https://www.cnblogs.com/Lanly/p/12257762.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   ~Lanly~  阅读(194)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.