CF1406 游记
鄙人打的第一场 cf ,还好遇到了一场比较简单的。
A Subset Mex
题意:给定可重集合 \(S\) ,将其分为两个集合 \(A\) 和 \(B\) ,使得 \(\operatorname{mex}(A)+\operatorname{mex}(B)\) 最大。
挺简单的一道签到题,贪心地想,如果一个数出现了大于两次,那么肯定两个集合各分配一个,如果只出现了一次,直接往一个集合怼就可以了。
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define ch() getchar()
#define pc(x) putchar(x)
template<typename T>inline void read(T&x){
int f;char c;
for(f=1,c=ch();c<'0'||c>'9';c=ch())if(c=='-')f=-f;
for(x=0;c<='9'&&c>='0';c=ch())x=x*10+(c&15);x*=f;
}
template<typename T>inline void write(T x){
static char q[64];int cnt=0;
if(!x)pc('0');if(x<0)pc('-'),x=-x;
while(x)q[cnt++]=x%10+'0',x/=10;
while(cnt--)pc(q[cnt]);
}
int cnt[105];
int main(){
int T;read(T);
while(T--){
memset(cnt,0,sizeof cnt);
int n;read(n);
for(int i=1;i<=n;++i){
int a;read(a);++cnt[a];
}
int o=0;
while(cnt[o]>=2)++o;
int oo=o;
while(cnt[oo]>=1)++oo;
write(o+oo),pc('\n');
}
return 0;
}
B Maximum Product
题意:给定 \(n\) 个数,选出 \(5\) 个数使得其乘起来最大。
考虑到:
直接 dp 记录最大值最小值即可。
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define ch() getchar()
#define pc(x) putchar(x)
template<typename T>inline void read(T&x){
int f;char c;
for(f=1,c=ch();c<'0'||c>'9';c=ch())if(c=='-')f=-f;
for(x=0;c<='9'&&c>='0';c=ch())x=x*10+(c&15);x*=f;
}
template<typename T>inline void write(T x){
static char q[64];int cnt=0;
if(!x)pc('0');if(x<0)pc('-'),x=-x;
while(x)q[cnt++]=x%10+'0',x/=10;
while(cnt--)pc(q[cnt]);
}
long long mx[6],mn[6];
int main(){
int T;read(T);
while(T--){
memset(mx,-0x3f,sizeof mx);
memset(mn,0x3f,sizeof mn);
mx[0]=mn[0]=1;int n;read(n);
for(int i=1;i<=n;++i){
long long a;read(a);
for(int j=min(i,5);j>=1;--j){
mx[j]=max(mx[j],max(mx[j-1]*a,mn[j-1]*a));
mn[j]=min(mn[j],min(mx[j-1]*a,mn[j-1]*a));
}
}
write(mx[5]),pc('\n');
}
return 0;
}
C Link Cut Centroids
题意等价于:给定一棵 \(n\) 个点的树,请断掉一条边再加上一条边,使得得到的还是一棵树,同时重心唯一。
如果重心本来就唯一,删掉一条边再连回去就可以了,如果重心不唯一,由于 \(n\ge 3\) ,重心肯定不是叶子节点,把一个重心的某条边(不是连接两个重心的那条边)连出去的子树接到另一棵子树上就行了,正确性显然。
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define ch() getchar()
#define pc(x) putchar(x)
template<typename T>inline void read(T&x){
int f;char c;
for(f=1,c=ch();c<'0'||c>'9';c=ch())if(c=='-')f=-f;
for(x=0;c<='9'&&c>='0';c=ch())x=x*10+(c&15);x*=f;
}
template<typename T>inline void write(T x){
static char q[64];int cnt=0;
if(!x)pc('0');if(x<0)pc('-'),x=-x;
while(x)q[cnt++]=x%10+'0',x/=10;
while(cnt--)pc(q[cnt]);
}
const int maxn=100005;
struct Edge{
int v,nt;
Edge(int v=0,int nt=0):
v(v),nt(nt){}
}e[maxn*2];
int hd[maxn],num;
void qwq(int u,int v){
e[++num]=Edge(v,hd[u]),hd[u]=num;
}
int sz[maxn];
void getsize(int u,int fa){
sz[u]=1;
for(int i=hd[u];i;i=e[i].nt){
int v=e[i].v;
if(v==fa)continue;
getsize(v,u);sz[u]+=sz[v];
}
}
int r0,r1,n;
void findroot(int u,int fa){
for(int i=hd[u];i;i=e[i].nt){
int v=e[i].v;
if(v==fa||sz[v]*2<n)continue;
if(sz[v]*2>n)return findroot(v,u);
r0=u,r1=v;return;
}
r0=u;return;
}
int main(){
int T;read(T);
while(T--){
memset(hd,0,sizeof hd);num=0;
read(n);
for(int i=1;i<n;++i){
int u,v;
read(u),read(v);
qwq(u,v);qwq(v,u);
}
getsize(1,0);
r0=r1=0;
findroot(1,0);
if(!r1){
int x=1,y=e[hd[1]].v;
write(x),pc(' '),write(y),pc('\n');
write(x),pc(' '),write(y),pc('\n');
}
else{
int qaq=0;
for(int i=hd[r0];i;i=e[i].nt){
int v=e[i].v;
if(v!=r1){
qaq=v;
break;
}
}
write(r0),pc(' '),write(qaq),pc('\n');
write(r1),pc(' '),write(qaq),pc('\n');
}
}
return 0;
}
D Three Sequences
题意:给定长度为 \(n\) 数组 \(a\) ,构造两个长度为 \(n\) 的数组 \(b\) , \(c\) ,使得 \(\forall 1\le i\le n,a_i=b_i+c_i\) ,并且 \(b\) 单调不升, \(c\) 单调不降,并且 \(\max(b_i,c_i)\) 最小,有 \(q\) 次操作,每次操作都会给出 \(l,r,x\) ,令 \(\forall l\le i\le r,a_i\gets a_i+x\) ,对于每次操作,求出这次操作完后最小的 \(\max(b_i,c_i)\) 。
对 \(a\) 数组进行差分, \(b\) 相当于是除了第一个值以外后面的数都非正数, \(c\) 相当于是后面的都非负数,相当于是要最小化 \(\max(\sum_{i=1}^nb_i,c_1)\) ,对于任意的 \(i\ge 2\) ,如果 \(a_i\le 0\) ,肯定全部分配给 \(c_i\) ,否则全部分配给 \(b_i\) ,这样才能最小化 \(\sum_{i=2}^nb_i\) ,不妨设 \(s=\sum_{i=2}^nb_i\) ,那么相当于是要最小化 \(\max(b_1+s,c_1)\) ,其中 \(b_1+c_1=a_1\) ,当 \(b_1+s=c_1\) 时最小,但是注意到必须取整数,所以答案就是 \(\lceil\frac{a_1+s}{2}\rceil\) ,修改就是维护 \(s\) ,这个很简单。
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define ch() getchar()
#define pc(x) putchar(x)
template<typename T>inline void read(T&x){
int f;char c;
for(f=1,c=ch();c<'0'||c>'9';c=ch())if(c=='-')f=-f;
for(x=0;c<='9'&&c>='0';c=ch())x=x*10+(c&15);x*=f;
}
template<typename T>inline void write(T x){
static char q[64];int cnt=0;
if(!x)pc('0');if(x<0)pc('-'),x=-x;
while(x)q[cnt++]=x%10+'0',x/=10;
while(cnt--)pc(q[cnt]);
}
const int maxn=100005;
long long a[maxn];
long long ans(long long a,long long b){
return b+(((a-b)&1)?(a-b+1)/2:(a-b)/2);
}
int main(){
int n;read(n);
for(int i=1;i<=n;++i)
read(a[i]);
long long sum=0;
for(int i=n;i>=2;--i){
a[i]-=a[i-1];
if(a[i]>=0)sum+=a[i];
}
write(ans(a[1],sum));pc('\n');
int q;read(q);
while(q--){
int l,r;long long x;
read(l),read(r),read(x);++r;
if(l==1)a[l]+=x;
else{
if(a[l]>=0)sum-=a[l];
a[l]+=x;
if(a[l]>=0)sum+=a[l];
}
if(r<=n){
if(a[r]>=0)sum-=a[r];
a[r]-=x;
if(a[r]>=0)sum+=a[r];
}
write(ans(a[1],sum)),pc('\n');
}
return 0;
}
总结
E 我不会写,可以去看看 Imakf 的博客。
第一场 cf ,感觉题目难度对新手不错,在 B 上面卡了一下,其他题目感觉还是很好的。
一开始以为自己只能写出 AB ,结果一直切完了 D ,到 22:30 的时候,刚好把 E 题目看完,我已经没有时间再做了,于是就只好离场了( E 反正不会做)。
体验不错,题目蛮有意思的,不知道下次还能不再打,希望时间能都在 9:30 左右开始就好了。