Dashboard - Codeforces Round #807 (Div. 2) - Codeforceshttps://codeforces.com/contest/1705。。。9点场看成10点场,拿小号打最后一小时,按速度来说应该能吃分的。。。
A. Mark the Photographer
排序以后直接模拟判断就好了
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
const int maxn = 1e3+10;
int num[maxn];
int main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t;
cin>>t;
while(t--){
int n,x;
cin>>n>>x;
for(int i = 1;i<=n*2;i++)
cin>>num[i];
sort(num+1,num+2*n+1);
int j = 1;
for(int i = 1;i<=n;i++)
if(num[i+n]-num[i]<x){
j = 0;
break;
}
if(j)
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
}
B. Mark the Dust Sweeper
贪心一下,最理想的情况肯定是每个房间-1,最后一个房间+1,为了达成这种情况就把最左边非0房间到最后一个房间之间为0的房间操作一下,比如 0 2 0 2 先变成 0 1 1 2然后第二个第三个房间的内容都能直接扔到最后一个房间
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
const int maxn = 1e6+10;
int num[maxn];
int main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t;
cin>>t;
while(t--){
int n;
cin>>n;
for(int i = 1;i<=n;i++)
cin>>num[i];
long long ans = 0;
int j = 0;
int nn = 0;
for(int i = 1;i<n;i++){
if(!j&&num[i]>0){
j = 1;
}
if(j&&num[i]==0)
nn++;
}
for(int i = 1;i<n;i++)
ans+=num[i];
ans+=nn;
cout<<ans<<endl;
}
}
C. Mark and His Unfinished Essay
这题的思路属于一个函数映射,基础条件是c很小。如果询问的下标在起始长度内,可以直接得到答案,如果不是,就要一层层映射回去直到找到原始字符串的位置。比如样例的markmark(1-4复制一次),我询问下标6,根据复制了1-4可知,下标6是映射了下标2的内容。具体映射函数关系为先二分找到对应下标i是在哪一次复制中产生的,再减去前一次复制的最终长度+1,再加上本次对应复制范围的起始下标。比如上述提到的2 = 6-(4+1)+1。绘图理解一下最好。
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
const int maxn = 1e6+10;
int num[maxn];
int main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t;
cin>>t;
while(t--){
int n,c,q;
cin>>n>>c>>q;
string s;
cin>>s;
long long l,r;
long long len[100] = {};
pair<long long,long long>ch[100] = {};
len[1] = n;
int tar = 1;
for(int i = 1;i<=c;i++){
cin>>l>>r;
ch[tar] = {l,r};
len[tar+1] = r-l+len[tar]+1;
++tar;
}
for(int i = 1;i<=q;i++){
cin>>l;
long long now = l;
while(now>n)
{
int pos = lower_bound(len+1,len+tar+1,now)-len;
pos--;
now = now-len[pos]-1+ch[pos].first;
//cout<<now<<" "<<len[pos]<<" "<<ch[pos].first<<endl;
}
cout<<s[now-1]<<endl;
}
}
}
D. Mark and Lightbulbs
补出来的。这个操作其实可以看成,它可以衍生1串,即01000可以变成01100也可以变成00100,
就是可以把它变长/变短/移动,但是不能分裂,即 01000 不能变成01010这种情况
然后-1的情况就两种,1串个数不同/首尾不同。
再考虑操作次数,在纸上模拟一下就发现,是1串首尾长度-对应1串首尾长度。
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
const int maxn = 1e6+10;
int num[maxn];
int main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t;
cin>>t;
while(t--) {
int n;
cin >> n ;
string s1,s2;
cin>>s1>>s2;
vector<pair<int,int>>v1,v2;
if(s1[0]!=s2[0]||s1[n-1]!=s2[n-1]){
cout<<-1<<endl;
continue;
}
int j = 0;
for(int i = 0;i<n;i++){
if(s1[i]=='1'&&j==1){
v1.back().second++;
}
else if(s1[i]=='1'&&j==0){
v1.push_back({i,i});
j = 1;
}
if(s1[i]=='0'&&j==1){
j = 0;
}
}
j = 0;
for(int i = 0;i<n;i++){
if(s2[i]=='1'&&j==1)
v2.back().second++;
if(s2[i]=='1'&&j==0){
v2.push_back({i,i});
j = 1;
}
if(s2[i]=='0'&&j==1){
j = 0;
}
}
if(v1.size()!=v2.size()){
cout<<-1<<endl;
continue;
}
long long ans = 0;
for(int i = 0;i<v1.size();i++){
ans+=abs(v1[i].first-v2[i].first);
ans+=abs(v1[i].second-v2[i].second);
}
cout<<ans<<endl;
}
}
//这个操作最终能实现的是1串伸长/简短/移动
//为什么不考虑0串:01串 1串动0也动,相对的
//次数怎么算:按最快考虑 01000->00100要两次,01100->00110要2次,即1串首位-变后1串首位取abs