Codeforces Global Round 16 ABCDE题解(更新ing)
继续开启掉分之旅,,只搞出了ABCD1太菜了,快掉到pupil了【😭】
A水题
B可以想到直接整段的MEX为2,同时发现把所有连续111分成一段MEX=0,连续000分成一段MEX=1,那么比较2和000段多少就可以。
点击查看代码
lude<iostream>
#include<algorithm>
#include<cstring>
#include<stack>
#include<bitset>
#include<queue>
#include<vector>
#include<cstdio>
#include<set>
#include<map>
#include<cmath>
using namespace std;
char ss[100005];
int main(){
int t;
scanf("%d",&t);
while(t--) {
scanf("%s",ss+1);
int n = strlen(ss+1);
int lin = 0;
for(int i=1;i<=n;i++) {
if(ss[i]=='0') {
lin++;
while(i<n&&ss[i+1]=='0') i++;
}
}
printf("%d\n",min(2,lin));
}
return 0;
}
C 分为00,01,11三种type,然后发现01分段ans+=2,00分段ans+=1,对于11如果能找到最近的一个00搞在一起可以ans+=1,否则弃之。
点击查看代码
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stack>
#include<bitset>
#include<queue>
#include<vector>
#include<cstdio>
#include<set>
#include<map>
#include<cmath>
using namespace std;
char A[100005],B[100005];
bool fla[100005];
int ty[100005],ans;
int les = 0;
int main(){
int t;
scanf("%d",&t);
while(t--) {
int n; scanf("%d",&n);
scanf("%s%s",&A[1],&B[1]);
les = 0; ans = 0;
for(int i=1;i<=n;i++) {
int a = A[i]-'0';
int b = B[i]-'0';
int tt;
if(a+b==0) tt = 1; //00
else if(a+b==1) tt = 2; //01
else tt = 3; //11
ty[i] = tt;
fla[i] = 0;
}
fla[n+1] = ty[n+1] = ty[0] = 0;
for(int i=1;i<=n;i++) {
if(ty[i]==2) ans += 2;
else if(ty[i]==1) ans+=1;
else if(ty[i]==3) {
if(ty[i-1]==1&&(!fla[i-1])) ans++,fla[i-1]=1;
else if(ty[i+1]==1&&(!fla[i+1])) ans++,fla[i+1]=1;
}
}
printf("%d\n",ans);
}
return 0;
}
D1 以ai为第一关键字,id(次序)为第二关键字,排序之后模拟就可以了。
D2 我们发现同一个value的所有人都是在一段座位的id上的,他们要么是一段的后缀,或者占满整行,或者是前缀。可以想到先倒着将后缀填满,再填满整行最后填前缀是最好的。所以我们用这个思想找到最后的答案就可以了。
点击查看代码
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stack>
#include<bitset>
#include<queue>
#include<vector>
#include<cstdio>
#include<set>
#include<map>
#include<cmath>
using namespace std;
struct node {
int a,id;
}z[100005];
int t,n,m,tot;
int ans;
bool cmp(node aa,node bb) {
if(aa.a!=bb.a) return aa.a<bb.a;
return aa.id < bb.id;
}
int main(){
scanf("%d",&t);
while(t--) {
scanf("%d%d",&n,&m);
tot = n*m; ans = 0;
for(int i=1;i<=tot;i++) {
scanf("%d",&z[i].a); z[i].id = i;
}
sort(z+1,z+1+tot,cmp);
for(int i=0;i<tot;i+=m) {
for(int j=1;j<m;j++) {
for(int k=j+1;k<=m;k++) {
if(z[i+j].a!=z[i+k].a&&z[i+j].id<z[i+k].id) ans++;
}
}
}
printf("%d\n",ans);
}
return 0;
}
E 一道思想题。。
我们其实发现只要一个结点没有叶子结点也就可以当做叶子来考虑(即把所有的芽一个一个全都靠在根结点上),这样做并不会使结局更差因为我们后面可以调整以达到最好状态。然后考虑把一个已经靠在根结点的芽给挂在某个叶子上时会使答案减1。所以如果我们设芽有k个(此时所说的芽是在完全调整到根节点之后的芽个数),那么如果有靠在根上的叶结点答案 n-2*k-1,即n减去根节点1减去芽k再k个芽靠k次叶子减k。如果没有靠在根上的叶子那么n-2*k就好了,因为只有k-1个芽靠在叶子上,剩下一个芽还要留在根上。
点击查看代码
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stack>
#include<bitset>
#include<queue>
#include<vector>
#include<cstdio>
#include<set>
#include<map>
#include<cmath>
using namespace std;
const int maxn = 2e5+5;
vector<int>ve[maxn];
int n;
int ty[maxn];//1 lef 2 bud
void dfs(int x,int pre) {
bool leavson = 0;
for(int y:ve[x]) {
if(y==pre) continue;
dfs(y,x);
if(ty[y]==1) leavson = 1;
}
if(x!=1) {
if(leavson) ty[x] = 2;
else ty[x] = 1;
}
}
void solve() {
scanf("%d",&n);
for(int i=1;i<=n;i++) ve[i].clear();
for(int i=1;i<n;i++) {
int x,y; scanf("%d%d",&x,&y); ve[x].push_back(y);
ve[y].push_back(x);
}
dfs(1,0);
bool rtlv = 0;
for(int y:ve[1]) {
if(ty[y]==1) rtlv = 1;
}
int bud = 0;
for(int i=2;i<=n;i++) if(ty[i]==2) bud++;
if(rtlv) printf("%d\n",n-2*bud-1);
else printf("%d\n",n-2*bud);
}
int main(){
int t; scanf("%d",&t);
while(t--) solve();
return 0;
}