Dashboard - Codeforces Round #807 (Div. 2) - Codeforces

A. Mark the Photographer

题意:

个人,每个人的身高设为,现在要把这些人均匀的排成俩排,每排n个人,规定对于所有的,后排人的身高要比前排人的身高高x,问是否能满足?

知识点:贪心

思路:

把所有人按身高排序,前n小的依次排到前排,后n大的依次排到后排,依次判断每个位置是否满足条件,即可。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int N=1e5+5;
void solve(){int n,x;cin>>n>>x;int w=n;n<<=1;vector<int>a(n);for(int i=0;i<n;++i)cin>>a[i];sort(a.begin(),a.end());//排序for(int i=0;i<w;++i){if(a[i+w]-a[i]<x){//最大n个和最小n个依次比较cout<<"NO\n";//某一个不行就是NOreturn ;}}cout<<"YES\n";
}
int main(){ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);int _=1;cin>>_;while(_--){solve();}return 0 ;
}

B. Mark the Dust Sweeper

题意:

有一个长度为n的数组a,现在有一种操作如下

(1)选择一对,满足

(2)把

(3)把

问最少的操作次数,使得

知识点:思维

思路:

发现对于一个不是0的数字来说,要让他变成0,如果他后面到n为止的数字都不是0,他只需要操作次,如果后面有0,需要一次操作去补上,所以我们只要从1开始往后看,看到第一个不是0的数字,他要操作次,操作次数+=,往后如果有0,说明有数来补,操作次数++。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int N=1e5+5;
void solve(){int n;cin>>n;vector<int>a(n+1);for(int i=1;i<=n;++i)cin>>a[i];int ops=0;for(int i=1;i<=n;++i){if(a[i]){//找到第一个不是0的数字在哪里ops=i;break;}}if(ops==0||ops==n){//如果在n或者没有,说明不需要操作cout<<0<<'\n';return ;}ll ans=0;for(int i=ops;i<n;++i){if(a[i])ans+=a[i];//a_i有数,操作次数+=a_ielse ans++;//a_i==0,有数字来补,额外操作一次}cout<<ans<<'\n';
}
int main(){ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);int _=1;cin>>_;while(_--){solve();}return 0 ;
}

C. Mark and His Unfinished Essay

题意:

现在有一个字符串s,现在可以操作c次,每次操作如下

(1)在字符串s中选择一对的子串t,把他拼接到字符串s后面形成新的s(s=s+t)

现在有q次询问,每次询问一个x,表示问s[x]=?

知识点:递归

思路:

如果查询的x就在最开始的字符串上,我们直接输出s[x],

如果在操作一次后的字符串上,我们看位置,

如果不在新加的字符串t上,那还是在最开始的字符串上,

如果在新加的字符串t上,因为新加的字符串t是最初字符串s的子串,所以我们还是可以在最开始的字符串上找到,图示如下

查7这个位置,我们相对于绿色方框的字符串的位置在哪里?

位置就是本身减去(上一个字符串长度-本次查询的左端点+1)

这样,我们大小问题就都搞清楚了,直接递归就行了。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int N=1e5+5;
ll dl[45],sl[45];
string s;
char Find(ll ops,ll now){if(now==0)return s[ops];//如果now==0,那就是原串,直接输出位置if(ops>dl[now-1])return Find(ops-sl[now],now-1);//如果不在上一个串的原串里,更新else return Find(ops,now-1);//在上一个串的原串里,直接看
}
void solve(){ll n,c,q;cin>>n>>c>>q;cin>>s;s="#"+s;//把下标改成1开始dl[0]=n;sl[0]=n;//初始化for(int i=1;i<=c;++i){ll l,r;cin>>l>>r;dl[i]=dl[i-1]+(r-l+1);//每次操作完后字符串的长度sl[i]=dl[i-1]-l+1;//这是不在原串里,每次下标更新的位置}while(q--){ll x;cin>>x;cout<<Find(x,c+1)<<'\n';//输出答案}
}
int main(){ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);int _=1;cin>>_;while(_--){solve();}return 0 ;
}

D. Mark and Lightbulbs

题意:

现在有一个长度为n的01串s,现在有一个操作,如下

(1)选择一个,并且

(2)把满足条件的异或1

现在给你一个长度为n的01串t,问最少的操作数把字符串s变成字符串t,如果不能输出-1

知识点:思维

思路:

我们首先可以发现,i=1和i=n这俩个位置十分滴特殊,什么情况下都不可以操作,就是一开始是什么,最后也是什么,所以我们可以直接判断,如果开始这俩个位置在串s和串t就不一样,那就是输出-1。

然后,我们如果把连续的1看成一个联通块,那么不论怎么操作,开始联通块是几个,最后联通块还是几个(条件使然),所以我们把s中1的联通块个数,和每一个联通块的左右端点记录一下(一会要用),再把t的也记录一下,如果s中1的联通块个数和t不等,那一定不能成立,输出-1.

接下来就都是成立的情况了,发现一个联通块可以把他左边的0变成1,也可以把左边的1变成0,右边也一样,也就是说,如下

下面这个变成上面的,

先左加满,再把右边多余的删掉,

现在有多次的移动,我们要让答案最小,肯定是上面第一个联通块和下面第一个联通块匹配(因为他们也交叉不了啊),如果上面第二个和下面第一个匹配,那上面第一个就自闭了。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int N=1e5+5;
struct dd{int l,r;
};
void solve(){int n;cin>>n;int pre=-1,prel=0;vector<dd>v,w;for(int i=1;i<=n;++i){//统计字符串s,1的联通块数量char o;cin>>o;int x=o-'0';if(x==pre)continue;else {if(pre==1)v.push_back({prel,i-1});prel=i;pre=x;}}if(pre==1)v.push_back({prel,n});pre=-1;prel=0;for(int i=1;i<=n;++i){//统计字符串t,1的联通块数量char o;cin>>o;int x=o-'0';if(x==pre)continue;else {if(pre==1)w.push_back({prel,i-1});prel=i;pre=x;}}if(pre==1)w.push_back({prel,n});int len=v.size(),tmp=w.size();if(len!=tmp)cout<<"-1\n";//如果两字符串1的联通块数量不同,那一定不行//如果俩字符串1位置的字符不同,也不行else if(len&&v[0].l!=w[0].l&&(v[0].l==1||w[0].l==1))cout<<"-1\n";//如果俩字符串最后位置的字符不同,也不行else if(len&&v[len-1].r!=w[len-1].r&&(v[len-1].r==n||w[len-1].r==n))cout<<"-1\n";else {ll ans=0;for(int i=0;i<len;++i){//统计操作次数ans+=abs(w[i].l-v[i].l);ans+=abs(w[i].r-v[i].r);}cout<<ans<<'\n';}
}
int main(){ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);int _=1;cin>>_;while(_--){solve();}return 0 ;
}

E. Mark and Professor Koro

题意:

有一个长度为n的数组a,有一种操作如下

(1)从数组a中找到某一个数x,出现了两次以上

(2)选两个x,从数组a中删除

(3)把数x+1,放入数组a中

现在有q次询问,每次询问前会把数组a中的赋值为l,

要询问改完的数组在操作到不能操作为止的最大值

知识点:二分,线段树

思路:

先来个比较好想的,复杂度  的,开始之前,我们先抽象一下题意

一个数x出现两次,数x+1出现次数+1,经过一定的思考,这不就是个模拟二进制吗,

我们把值域看成二进制的位数,第x位的次数=2了,进1,所以第x+1位的次数++

现在有个q次询问,每次询问前会把第a[k]位次数--,再把第l位的次数++,

二进制中某一位减怎么减呢,

如果这一位是1,那很简单把他变成0就行

如果这一位是0,那要先找比他位数高的距离他最近的1的位置,把那个位置变成0,这之间位置的数字变成1.

我们要先找到他前面1的位置,然后区间修改(就是区间异或1)

二进制中某一位加怎么加呢,

如果这一位是0,那很简单把他变成1就行

如果这一位是1,那要先找比他位数高的距离他最近的0的位置,把那个位置变成1,这之间位置的数字变成0.

我们要先找到他前面0的位置,然后区间修改(就是区间异或1)

最后答案就是最高位的1的位置。

怎么找当前位置前和他不同的数字在哪?我们可以前缀和+二分,前缀和表示每个位置到当前位置和他不同数字的个数,这个一定是单调的,我们要二分找的这个前缀和=1的位置就行了。

现在还有问题,我们怎么维护这个前缀和,线段树即可,区间修改,区间查询就都解决了。

最后答案也是二分找的只要看最后位置到那个位置的1的个数是1就行了

(注意,因为,线段树常数又有点大,所以有亿点点卡常)

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int N=2e5+155;
int has[N],a[N];
#define ls (i<<1)
#define rs ((i<<1)|1)
struct tre{int cnt0,cnt1,lazy;//维护区间0和1的个数
}tree[N<<2];
void work_lazy(int i,int l,int r){if(tree[i].lazy){swap(tree[l].cnt1,tree[l].cnt0);tree[l].lazy^=1;swap(tree[r].cnt1,tree[r].cnt0);tree[r].lazy^=1;tree[i].lazy=0;}
}
void push_up(tre &nowtre,tre ltre,tre rtre){nowtre.cnt0=ltre.cnt0+rtre.cnt0;nowtre.cnt1=ltre.cnt1+rtre.cnt1;
}
int query1(int l,int r,int i,int L,int R){//0和1分开查if(l>R||r<L)return 0;if(L<=l&&r<=R){return tree[i].cnt1;}work_lazy(i,ls,rs);int mid=l+r>>1;return query1(l,mid,ls,L,R)+query1(mid+1,r,rs,L,R);
}
int query0(int l,int r,int i,int L,int R){//0和1分开查if(l>R||r<L)return 0;if(L<=l&&r<=R){return tree[i].cnt0;}work_lazy(i,ls,rs);int mid=l+r>>1;return query0(l,mid,ls,L,R)+query0(mid+1,r,rs,L,R);
}
void change(int l,int r,int i,int L,int R){//修改其实就是交换区间0和1的个数if(l>R||r<L)return ;if(L<=l&&r<=R){swap(tree[i].cnt0,tree[i].cnt1);tree[i].lazy^=1;return ;}work_lazy(i,ls,rs);int mid=l+r>>1;change(l,mid,ls,L,R);change(mid+1,r,rs,L,R);push_up(tree[i],tree[ls],tree[rs]);
}
void build(int l,int r,int i){if(l==r){tree[i].cnt0=(has[l]==0);tree[i].cnt1=(has[l]==1);return ;}int mid=l+r>>1;build(l,mid,ls);build(mid+1,r,rs);push_up(tree[i],tree[ls],tree[rs]);
}
void dec(int x){//当前位置要减if(query1(1,N,1,x,x))change(1,N,1,x,x);//如果是1,直接改成0else {int l=x+1,r=N-1,mid,ans=0;while(l<=r){mid=l+r>>1;if(query1(1,N,1,x,mid)){r=mid-1;ans=mid;}else l=mid+1;}change(1,N,1,x,ans);}
}
void add(int x){//当前位置要加if(query0(1,N,1,x,x))change(1,N,1,x,x);//如果是0,直接改成1else {int l=x+1,r=N-1,mid,ans=x;while(l<=r){mid=l+r>>1;if(query0(1,N,1,x,mid)){r=mid-1;ans=mid;}else l=mid+1;}change(1,N,1,x,ans);}
}
void solve(){int n,q;cin>>n>>q;for(int i=1;i<=n;++i){cin>>a[i];has[a[i]]++;//当前位置个数++}for(int i=1;i<N;++i){has[i+1]+=has[i]/2;has[i]%=2;//弄成二进制}build(1,N,1);while(q--){int k,w;cin>>k>>w;dec(a[k]);//先减a[k]=w;//赋值add(a[k]);//再加int l=1,r=N-1,mid,ans=0;while(l<=r){//二分找答案mid=l+r>>1;if(query1(1,N,1,mid,N-1)){l=mid+1;ans=mid;}else r=mid-1;}cout<<ans<<'\n';}
}
int main(){ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);int _=1;//cin>>_;while(_--){solve();}return 0 ;
}

其实,可以优化到,我们把在外面的二分扔进权值线段树里就行了,代码的话,我等等写一下。

Codeforces Round #807 (Div. 2)A~E个人题解相关推荐

  1. Codeforces Round #807 (Div. 2)(A-D)

    Dashboard - Codeforces Round #807 (Div. 2) - CodeforcesCodeforces. Programming competitions and cont ...

  2. Codeforces Round #807 (Div. 2) A-C题解

    Codeforces Round #807 (Div. 2) A.B.C题题解 A - Mark the Photographer 题意:马克要给2n个人照相,分两排,一排站n人,给出每个人的身高,要 ...

  3. Codeforces Round #807 (Div. 2) A-D

    Codeforces Round #807 (Div. 2) A. Mark the Photographer 给定整数n,数组长度2*n,问能不能拆成两个长度为n的数组,两个数组的第i项有a[i]& ...

  4. Codeforces Round #807 (Div. 2) A - D

    Codeforces Round #807 (Div. 2) 提交情况 参考 Codeforces Round #807 (Div. 2) A~E A. Mark the Photographer 标 ...

  5. Codeforces Round #706 (Div. 2)-A. Split it!-题解

    目录 Codeforces Round #706 (Div. 2)-A. Split it! Problem Description Input Output Sample Input Sample ...

  6. Codeforces Round #742 (Div. 2) B、C 题解

    Codeforces Round 742 B. MEXor Mixup 题意 有一个数组,输入两个数a,b,a代表这个数组之外的最小非负整数,b代表这个数组的异或值,问你该数组的最小长度. 思路 首先 ...

  7. Codeforces Round #807 (Div. 2)补题

    C. Mark and His Unfinished Essay https://codeforces.com/contest/1705/problem/C 会卡long long,下面解法62ms过 ...

  8. Codeforces Round #807 (Div. 2) A-C

    目录 题目 A. Mark the Photographer 题意: 思路: code: B. Mark the Dust Sweeper 题意: 思路: code: C. Mark and His ...

  9. Codeforces Round #807 (Div. 2) E. Mark and Professor Koro(线段树二分)

    E. Mark and Professor Koro 题意 给定一个长度为n的数组,有q次更新操作,每次更新会将下标为k的元素的值更新为l,数组的更新是永久的.将数组更新后假设重复做以下操作,求可以得 ...

最新文章

  1. 和老同事的谈话:关于职业生涯以及MDA
  2. Mac和 iOS 下的对称和非对称加密算法的使用
  3. 图片操作scipy.ndimage.imread和scipy.misc.imresize
  4. 何为TransmittableThreadLocal
  5. 常系数齐次线性递推学习笔记
  6. PHP 完整实战23种设计模式
  7. 数据流图 系统流程图 程序流程图 系统结构图联系与区别
  8. 如何获取投票提交地址_简单实用 | 2019全国医院擂台赛投票攻略(县域版)
  9. 请问学习前端最有效的办法是什么?
  10. python计数循环,python - Python中的密码求解器循环计数 - SO中文参考 - www.soinside.com...
  11. qt自带的文档系统软件叫什么名字_翻译 | 为什么QObject子类不可复制?
  12. python请输入星期几的第一个_python如何获取星期几
  13. MSDN精选:Lambda 表达式(C# 编程指南)
  14. 第七周 项目4 - 队列数组
  15. 腾讯蔡晨:十年沉淀,腾讯iOA为企业安全保驾护航
  16. 项目管理杂谈-需求无止境
  17. vscode搭建c++开发环境
  18. 各数据库远程连接及ipv6环境配置
  19. MOSFET原理学习
  20. 离散制造,重复制造和流程制造总结

热门文章

  1. linux 使用dmidecode查看设备序列号
  2. 修改xampp中的mysql的密码报错,ERROR 1348 (HY000): Column 'Password' is not updatable
  3. Android10有sdcard读写权限,仍无法读写sdcard中文件问题解决
  4. studing method for linux
  5. iphone6+总显示无服务器,iphone6一直显示无服务为什么啊
  6. ubuntu20.04安装mysql8
  7. WinRAR 破解方法详解.-----------超级简单 1分钟搞定~
  8. C++课后作业 3. 教材习题4_8:定义Dog类,包含age和weight信息
  9. UltraEdit mac版破解方法
  10. 朋友圈集赞万能截图生成器威信小程序源码下载