zoukankan      html  css  js  c++  java
  • 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\) 个数使得其乘起来最大。

    考虑到:

    \[a<b\Leftrightarrow\begin{cases}a\cdot c<b\cdot c & c>0 \\ a\cdot c>b\cdot c & c<0 \end{cases} \]

    直接 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;
    }
    

    题意等价于:给定一棵 \(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 左右开始就好了。

  • 相关阅读:
    java对象存储管理
    Linux下添加新硬盘,分区及挂载
    挂载磁盘
    安装JDK
    RESTful架构详解
    java的编程习惯影响程序性能
    spring boot中的约定优于配置
    java8新特性:interface中的static方法和default方法
    约定优于配置的概念与思考
    java的数据类型:基本数据类型和引用数据类型
  • 原文地址:https://www.cnblogs.com/lsq147/p/13661861.html
Copyright © 2011-2022 走看看