zoukankan      html  css  js  c++  java
  • CodeForces 1406

    (注:本来开了个坑,原标题为「do you know wtf it is???」,正文为「懵逼了吧」,所以被 hsc 骂了……)

    这场比较简单,所以本文的重心放在一波三折的比赛(赛后?)经历上(

    本来想着用 tzcWh... 这个号控制住不要上橙,大概控制在 2070~2099 左右,然后下一场 div. 2 就能超过大号这样。

    比赛结束前 5min E 交上去 WA 了,于是弃了,看了眼 predictor,能直接上 2150,这不行啊。于是开始故意 hack 失败,网速比较慢所以 5min 只 hack 了 5 次。

    减了 250pts 之后比赛结束,又看了一眼 predictor,+130?掐指一算,涨到 2102?wtf???要上橙就给我上高一点,要么就不要上橙,ntm 给我搭个橙名线是几个意思?很后悔没有早点开始 hack,多 hack 一次就 CM 稳了。然后就跟 wjz 疯狂祖安。

    然后突然发现我的 A 好像 FST 了,上面出现了个红色的 -1?那 tgxl,rating 低一点没关系,至少不用上橙了!然后 wjz 说「这是 feature,你刷新一下」(老 system test 观众了),然后又没 FST,得分了。还我 FST!!!于是继续祖安,祖安累了去洗了个澡。

    洗完澡回来之后发现 wjz 跟我说「不会 master」,又是啥?system test 已经结束了,打开 predictor 一看 +124,2096?tgxl,这个结果我满意。于是开开心心睡觉去了。

    早上起来忐忑地打开电脑,发现居然 +127,2099?这无疑是我最满意的结果,请叫我控分带师(

    也许这就是命运吧(


    下面是题解(正文部分)

    CF 比赛页面传送门

    A - Subset Mex

    洛谷题目页面传送门 & CF 题目页面传送门

    给定一个集合 (a,|a|=n),将它分成两个集合 (A,B),要求最大化 (operatorname{mex}(A)+operatorname{mex}(B))。本题多测。

    (nin[1,100],a_iin[0,100],Tin[1,100])

    随便贪心就好了,两个集合的 (operatorname{mex}) 齐头并进,某个进不了了就停下来,两个都停下来的时候就是答案最大化的情况。代码也随便写了吧。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=100;
    int n;
    int a[N+1];
    int cnt[N+1];
    void mian(){
    	cin>>n;
    	for(int i=1;i<=n;i++)cin>>a[i];
    	sort(a+1,a+n+1);
    	memset(cnt,0,sizeof(cnt));
    	for(int i=1;i<=n;i++)cnt[a[i]]++;
    	int fst=0;
    	for(int i=0;i<=100;i++)if(cnt[i]<2){fst=i;break;}
    	for(int i=fst;i<=100;i++)if(cnt[i]<1)return cout<<fst+i<<"
    ",void();
    	if(fst)cout<<fst+101<<"
    ";
    	else cout<<202<<"
    ";
    }
    int main(){
    	int testnum=1;
    	cin>>testnum;
    	while(testnum--)mian();
    	return 0;
    }
    

    B - Maximum Product

    洛谷题目页面传送门 & CF 题目页面传送门

    给定 (n) 个整数(可正可负可零),求其中 (5) 个数的乘积的最大值。本题多测。

    (ninleft[5,10^5 ight],sum nleq 2 imes10^5)

    这个就分个两种情况吧,有 (0) 和无 (0)

    (0) 的话就是 (0) 了。

    (0) 的话就枚举正数个数,然后排个序贪个心就切了。

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    #define pb push_back
    const int inf=0x3f3f3f3f3f3f3f3f;
    int n;
    void mian(){
    	cin>>n;
    	vector<int> po,ne;
    	int ans=-inf;
    	for(int i=1;i<=n;i++){
    		int x;
    		cin>>x;
    		if(x>0)po.pb(x);
    		if(x==0)ans=0;
    		if(x<0)ne.pb(x);
    	}
    	sort(po.begin(),po.end(),greater<int>());
    	sort(ne.begin(),ne.end());
    	for(int i=0;i<=5;i++){
    		if(i<=po.size()&&5-i<=ne.size()){
    			int res=1;
    			if(5-i&1){
    				for(int j=(int)(po.size())-1;j>=(int)(po.size())-i;j--)res*=po[j];
    				for(int k=(int)(ne.size())-1;k>=(int)(ne.size())-(5-i);k--)res*=ne[k];
    			}
    			else{
    				for(int j=0;j<i;j++)res*=po[j];
    				for(int k=0;k<5-i;k++)res*=ne[k];
    			}
    			ans=max(ans,res);
    		}
    	}
    	cout<<ans<<"
    ";
    }
    signed main(){
    	int testnum=1;
    	cin>>testnum;
    	while(testnum--)mian();
    	return 0;
    }
    

    洛谷题目页面传送门 & CF 题目页面传送门

    给定一棵大小为 (n) 的树。要求删掉一条边加上一条边使重心唯一。给出方案。本题多测。

    (ninleft[3,10^5 ight],sum nleq 10^5)

    假如说本来就唯一的话不用说。否则:

    显然两个重心相邻。钦定其中一个为根,那么另一个就是第 (2) 层。我也不知道怎么想出来的,就随便试吧,可以删掉第 (2) 层重心的任意一条通向儿子的边(由 (ngeq 3) 易证一定有儿子),然后把那个儿子连向根即可。

    证明的话,显然删加过之后根依然是重心,因为子树大小最大值变小了嘛。而第 (2) 层那个的相对应的显然变大了,那么它们的最大子树大小就不等了,就不可能同时为重心。然后如何证其他点不为重心呢?因为要想是重心就必须与根相邻,而这三个点发生关系跟其他儿子有个屁的关系,那最大子树大小肯定就不变啊,就无法翻身。得证。

    #include<bits/stdc++.h>
    using namespace std;
    #define pb push_back
    const int N=100000;
    int n;
    vector<int> nei[N+1];
    int sz[N+1];
    void dfs(int x=1,int fa=0){
    	sz[x]=1;
    	for(int i=0;i<nei[x].size();i++){
    		int y=nei[x][i];
    		if(y==fa)continue;
    		dfs(y,x);
    		sz[x]+=sz[y];
    	}
    }
    void mian(){
    	cin>>n;
    	for(int i=1;i<=n;i++)nei[i].clear();
    	for(int i=1;i<n;i++){
    		int x,y;
    		scanf("%d%d",&x,&y);
    		nei[x].pb(y);nei[y].pb(x);
    	}
    	dfs();
    	vector<int> cen;
    	for(int i=1;i<=n;i++){
    		bool flg=true;
    		int sum=1;
    		for(int j=0;j<nei[i].size();j++){
    			int x=nei[i][j];
    			if(sz[x]>sz[i])continue;
    			flg&=sz[x]<=n/2;
    			sum+=sz[x];
    		}
    		flg&=n-sum<=n/2;
    		if(flg)cen.pb(i);
    	}
    	assert(cen.size()<=2);
    	if(cen.size()==1)printf("%d %d
    %d %d
    ",1,nei[1][0],1,nei[1][0]);
    	else{
    		int son=nei[cen[0]][0]==cen[1]?nei[cen[0]][1]:nei[cen[0]][0];
    		printf("%d %d
    %d %d
    ",cen[0],son,cen[1],son);
    	}
    }
    int main(){
    	int testnum=1;
    	cin>>testnum;
    	while(testnum--)mian();
    	return 0;
    }
    

    D - Three Sequences

    洛谷题目页面传送门 & CF 题目页面传送门

    给定一个长度为 (n) 的数列 (a)。你需要构造出长度为 (n) 的数列 (b,c),满足 (a_i=b_i+c_i),且 (b) 不降,(c) 不升。最小化 (max(b_i,c_i))。然后还有 (q) 次区间增加,每次输出最小化的结果。

    (n,qinleft[1,10^5 ight])

    二话不说先找结论啊。通过观察样例发现,一开始 (b_1,c_1) 随便取只要满足 (a_1=b_1+c_1) 即可,然后以后的话,若 (a) 的增量 (geq 0) 就在 (b) 上加,否则就在 (c) 上减。证明的话随便想想很简单,显然 (max(b_i,c_i)=max(b_n,c_1)),那么在 (b_1,c_1) 固定的时候,(b) 的总增量显然越小越好,于是就只有在必要的时候才在 (b) 上加咯。

    然后现在解决 (b_1,c_1) 不固定的事情。我们想要令 (max(b_n,c_1)) 这个柿子最小,那么首先需要将 (b_n)(b_1) 表示一下。令增量 (Delta_i=a_{i+1}-a_i),则 (b_n=b_1+sumlimits_{i=1}^{n-1}[Delta_igeq 0]Delta_i)。令那个 (sum)(Sigma),那么柿子为 (max(b_1+Sigma,c_1))。又 (a_1=b_1+c_1),则柿子又可以写为 (max(b_1+Sigma,a_1-b_1))。那么注意到 (max) 两个参数是和为常量的,那么最理想的情况是令它们相等,则 (max) 最小。解个方程可以得到 (b_1=dfrac{a_1-Sigma}2)。但是不允许出现小数,所以还要取个整然后左右两边 round 一下。

    然后还有区间加呢。注意到区间加只会令两个增量变化,于是随便 (mathrm O(1)) 维护即可。

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    const int inf=0x3f3f3f3f3f3f3f3f;
    const int N=100000;
    int n;
    int a[N+1];
    int qu;
    int d[N+1];
    int calc(int now,int x){
    	int res=inf;
    	for(int i=now-3;i<=now+3;i++)res=min(res,max(i+x,a[1]-i));
    	return res;
    }
    void mian(){
    	cin>>n;
    	for(int i=1;i<=n;i++)scanf("%lld",a+i);
    	for(int i=1;i<n;i++)d[i]=a[i+1]-a[i];
    	int x=0;
    	for(int i=1;i<n;i++)if(d[i]>0)x+=d[i];
    	cout<<calc(a[1]-x>>1,x)<<"
    ";
    	cin>>qu;
    	while(qu--){
    		int l,r,v;
    		scanf("%lld%lld%lld",&l,&r,&v);
    		if(l==1)a[1]+=v;
    		if(l-1&&d[l-1]>0)x-=d[l-1];
    		if(r<n&&d[r]>0)x-=d[r];
    		d[l-1]+=v,d[r]-=v;
    		if(l-1&&d[l-1]>0)x+=d[l-1];
    		if(r<n&&d[r]>0)x+=d[r];
    		printf("%lld
    ",calc(a[1]-x>>1,x));
    	}
    }
    signed main(){
    	int testnum=1;
    //	cin>>testnum;
    	while(testnum--)mian();
    	return 0;
    }
    

    E - Deleting Numbers

    这是钓鱼王子出的好题哦~

    洛谷题目页面传送门 & CF 题目页面传送门

    本题为交互题。给定 (n),初始时有 (A=[1,n]cap mathbb Z)。你有 (3) 种操作:

    1. 查询 (A) 中有多少个 (a) 的倍数((ain [1,n]));
    2. 查询 (A) 中有多少个 (a) 的倍数((ain[2,n])),并将 (A) 中所有 (a) 的倍数删去,特殊地,如果 (x)(a) 的倍数则不删;
    3. 得出答案 (a),操作之后立即结束。

    你需要在不超过 (10^4) 次操作内猜出某个预先设定好的 (xin A)

    (ninleft[2,10^5 ight])

    思路在于,通过操作 (1) 和操作 (2) 的配合,实现查询 (x) 是否是 (a) 的倍数。

    不难想到尝试将 (x) 分解质因数,根据弱智的唯一分解定理可以确定 (x)

    最 naive 的想法是每个质数的幂都试一遍。打个表发现 (pi(n)) 大概是 (9500+),然后质数的幂大概是 (9700) 左右个。你可能会说,噫,好,这场 div. 2 我阿克了!哦上帝,瞧瞧这天真的声音。注意到操作 (2) 是先返回结果再删除的,也就是说它的返回结果是个幌子,你想知道 ([amid x]) 必须要先 (2)(1)(2) 步走。

    想到寿司晚宴那题的一个结论:将质数分成小质数和大质数,则每个数最多含有一个大质因子。

    那么先将小质因子随便毛搞搞,我们设 ( au(m)) 表示 (m) 以内质数的幂的个数,那么是 (2 au(sqrt n)) 步的。实际上可以进一步优化,对于每个质数,先将它给 (2) 了,然后每个幂就可以直接查了。这样是 (pi(sqrt n)+ au(sqrt n)) 的。别看这一步优化微不足道,其实她能决定你是否 AC。

    现在把质因数分解式里的小质因子部分已经分解出来了,并且 (A) 里显然只剩下 (1)(x) 和所有大质数。接下来的任务就是要找出 (x) 是否有大质因子,如果有的话是谁。

    需要分出两种情况:

    1. 小质因子部分 (>1)。那么显然 (x) 是不属于那个大质数集的。那还怕个鬼啊,直接检查所有的大质数乘以小质因子部分是否剩一个数,剩的话大质因子就是他了乘上去,否则没有;
    2. 小质因子部分 (=1)。此时就需要害怕了,因为你「检查所有的大质数乘以小质因子部分是否剩一个数」的话,那你任何一次检查结果都是「是」,就无语了。而此时问题变得更加简单,剩下来的集合就是 (1) 和所有大质数,而你可以确定 (x) 就在里面。考虑对大质数序列分块。每块整体删一下,然后如果集合大小减少数量不对劲就说明 (x) 一定在这块里面,集中精力搞。由于块大小不大,可以直接逐个用操作 (1) 排查。总操作次数大约为 (pi(sqrt n)+ au(sqrt n)+(pi(n)-pi(sqrt n))+2sqrt{pi(n)-pi(sqrt n)}= au(sqrt n)+pi(n)+2sqrt{pi(n)-pi(sqrt n)}),卡的死死的,出题人真是毒瘤。
    #include<bits/stdc++.h>
    using namespace std;
    #define pb push_back
    bool ispr(int x){
    	if(x<2)return false;
    	for(int i=2;i*i<=x;i++)if(x%i==0)return false;
    	return true;
    }
    int A(int x){
    	printf("A %d
    ",x),fflush(stdout);
    	cin>>x;return x;
    }
    int B(int x){
    	printf("B %d
    ",x);fflush(stdout);
    	cin>>x;return x;
    }
    void C(int x){printf("C %d
    ",x);fflush(stdout);exit(0);}
    void mian(){
    	int n;
    	cin>>n;
    	if(n==1)C(1);
    	vector<int> pr;
    	for(int i=2;i<=n;i++)if(ispr(i))pr.pb(i);
    	int x=1,lim=sqrt(n);
    	for(int i=0;pr[i]<=lim;i++){
    		B(pr[i]);
    		int now=1;
    		while(now*pr[i]<=n)now*=pr[i];
    		while(now>1){
    			if(A(now)==1){x*=now;break;}
    			now/=pr[i];
    		}
    	}
    	vector<int> v;
    	for(int i=0;i<pr.size();i++)if(pr[i]>lim)v.pb(pr[i]);
    	if(x==1){
    		int now=A(1);
    		for(int i=0;i<v.size();i+=100){
    			for(int j=i;j<i+100&&j<v.size();j++)B(v[j]);
    			int res=A(1);
    			if(now-res==min(i+100,int(v.size()))-i)now=res;
    			else{
    				for(int j=i;j<i+100&&j<v.size();j++)if(A(v[j])==1){x=v[j];break;}
    				break;
    			}
    		}
    	}
    	else{
    		for(int i=0;i<v.size();i++)if(1ll*x*v[i]<=n&&A(x*v[i])==1){x*=v[i];break;}
    	}
    	C(x);
    }
    int main(){
    	int testnum=1;
    //	cin>>testnum;
    	while(testnum--)mian();
    	return 0;
    }
    
    珍爱生命,远离抄袭!
  • 相关阅读:
    11g RAC R2 体系结构---进程,日志
    Linux性能监控top及vmstat命令
    AIX性能监控topas命令的详细解析
    AIX 中 Paging Space 使用率过高的分析与解决
    fast_recovery_area无剩余空间(ORA-19815)
    Dataguard之redo传输服务
    Oracle 表的连接方式(2)-----HASH JOIN的基本机制3
    Oracle 表的连接方式(2)-----HASH JOIN的基本机制2
    全局对象
    什么是vuejs之重新认识vuejs
  • 原文地址:https://www.cnblogs.com/ycx-akioi/p/CodeForces-1406.html
Copyright © 2011-2022 走看看