[CF1088X]Codeforces Round #525 (Div. 2)

Posted by Dispwnl on December 5, 2018

感觉这场CF有点不够$Div2$难度啊……没打真是可惜了

恭喜$XG$大爷一场上紫!

A  Ehab and another construction problem

题目大意

找两个数$a,b$,使得

  • $1\le a,b\le x$
  • $b$能整除$a$
  • $a·b>x$
  • $\frac{a}{b}<x$

题解

枚举即可

代码

# include<bits/stdc++.h>
using namespace std;
int x;
int main()
{
	scanf("%d",&x);
	for(int i=1;i<=x;++i)
	  for(int j=i;j<=x;j+=i)
	    if(i*j>x&&j/i<x) return printf("%d %d",j,i),0;
	return printf("-1"),0;
}

B  Ehab and subtraction

题目大意

给定一个序列$a$,每次找到序列中最小的正整数(没有则为$0$),输出这个数并且序列中每个数都减去这个数,重复这样的操作$k$次

题解

这个值在原序列中肯定是单调递增的,排下序记录每次的答案扫一遍即可

代码

# include<bits/stdc++.h>
using namespace std;
const int MAX=1e5+5;
int n,k,ans;
int a[MAX];
int main()
{
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;++i)
	  scanf("%d",&a[i]);
	sort(a+1,a+1+n);
	for(int i=1,L=0;i<=k;++i)
	  {
	  	while(L<=n&&a[L]<=ans) ++L;
	  	if(L<=n) printf("%d\n",a[L]-ans),ans=a[L];
	  	else printf("0\n");
	  }
	return 0;
}

C  Ehab and another construction problem

题目大意

给定一个长度为$n$的序列$a$,有两种操作:

  • 选择前$i$个数同加$x(0\le x\le 10^6)$
  • 选择前$i$个数同对$x(1\le x\le 10^6)$取模

求一种方案使得在使用不超过$n+1$次操作后序列单调递增

题解

发现对$x$取模对于小于$x$的数是没有影响的

对于$a_i,a_{i+1}$,模数$x$需满足$a_i<x,a_{i+1}\% x>a_i$

所以先开始同加一个较大的数,每次对$a_i$取模$a_i-i+1$即可保证单调递增,操作数是$n$

代码

# include<bits/stdc++.h>
using namespace std;
const int MAX=2e3+5;
int n;
int a[MAX];
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;++i)
	  scanf("%d",&a[i]),a[i]+=2*n;
	printf("%d\n1 %d %d\n",n,n,2*n);
	for(int i=1;i<n;++i)
	  printf("2 %d %d\n",i,a[i]-i+1);
	return 0;
}

D  Ehab and another construction problem

题目大意

交互题

现在有两个数$a,b$,每次可以询问两个数$c,d$

  • 如果$a\oplus c>b\oplus d$,返回$1$
  • 如果$a\oplus c=b\oplus d$,返回$0$
  • 如果$a\oplus c<b\oplus d$,返回$-1$

要求你在少于$62$次操作中把$a,b$求出来

题解

假设我们已经知道$a,b$第$k$位以后各个位是多少(即知道忽略第$k$位之前$a,b$的大小),现在要搞第$k-1$位

如果第$k$位以后的$a!=b$,对于第$k-1$位,如果查询$(c+2^{k-1},d+2^{k-1})$

  • 如果返回$1$,说明$a_{k-1}=0$,$b_{k-1}$是多少可以通过查询$(c+2^{k-1},d)$得到
  • 如果返回$0$,说明前面的$a=b$,可以通过查询$(c+2^{k-1},d)$得到$a_{k-1},b_{k-1}$具体值
  • 如果返回$-1$,说明$b_{k-1}=0$,$a_{k-1}$是多少可以通过查询$(c+2^{k-1},d)$得到

初始的时候查询$(0,0)$得到$a,b$总的大小关系,然后一位位往前推即可

代码

# include<iostream>
# include<cstring>
# include<cstdio>
# include<algorithm>
using namespace std;
int query(int C,int D,int x=0)
{
	printf("? %d %d\n",C,D);
	fflush(stdout),scanf("%d",&x);
	return x;
}
int main()
{
	int c=0,d=0,a=0,b=0,fl=query(0,0);
	for(int i=29,w,qwq;i>=0;--i)
	  {
	  	w=(1<<i);
	  	if(!fl)
	  	{
	  		qwq=query(c+w,d);
	  		if(qwq==-1) a+=w,b+=w;
		}
		else if(fl==1)
		{
			fl=query(c+w,d+w);
			if(fl==-1) a+=w,c+=w,fl=query(c,d);
			else if((fl==1||!fl)&&query(c+w,d)==-1) a+=w,b+=w;
		}
		else if(fl==-1)
		{
			fl=query(c+w,d+w);
			if(fl==1) b+=w,d+=w,fl=query(c,d);
			else if((fl==-1||!fl)&&query(c+w,d)==-1) a+=w,b+=w;
		}
	  }
	return printf("! %d %d",a,b),0;
}

E  Ehab and another construction problem

题目大意

给定一棵树,找出$k$($k$不给定)个树上不重叠连通块$A$,使得$\frac{\sum_{i=1}^{k}A_i}{k}$最大

题解

找到树上权值和最大的连通块,然后贪心找树上有多少个权值和等于这个值的连通块

完了

代码

# include<bits/stdc++.h>
# define LL long long
using namespace std;
const int MAX=3e5+5;
LL inf=-1e18;
struct p{
	int x,y;
}c[MAX<<1];
int n,num,tot;
LL ans=inf;
int h[MAX],d[MAX],w[MAX];
void add(int x=0,int y=0)
{
	scanf("%d%d",&x,&y);
	c[++num]=(p){h[x],y},h[x]=num;
	c[++num]=(p){h[y],x},h[y]=num;
}
LL dfs(int x=1,int fa=0)
{
	LL sum=w[x];
	for(int i=h[x];i;i=c[i].x)
	  if(c[i].y^fa) sum+=max(0ll,dfs(c[i].y,x));
	return ans=max(ans,sum),sum;
}
LL dfs1(int x=1,int fa=0)
{
	LL sum=w[x];
	for(int i=h[x];i;i=c[i].x)
	  if(c[i].y^fa) sum+=max(0ll,dfs1(c[i].y,x));
	if(sum==ans) ++tot,sum=0;
	return sum;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;++i)
	  scanf("%d",&w[i]);
	for(int i=1;i<n;++i,add()); 
	return dfs(),dfs1(),printf("%I64d %d",ans*tot,tot),0; 
}