Ozon Tech Challenge 2020 (Div.1 + Div.2, Rated, T-shirts + prizes!)

contest1305

A.Kuroni and the Gifts
题意
给两个长度为n的数组a[],b[],保证在每个数组内任意两个元素不同,要求重新排列两个数组内元素使得对于任意 i , j i,j i,j a i + b i ! = a j + b j a_i+b_i!=a_j+b_j ai+bi!=aj+bj,输出重新排列的两个数组。

思路
直接对两个数组排序分别输出即可。

AC代码

#include
#include
#include
#include
#include
#include
#define MOD 1000000007
using namespace std;
int main()
{
	int t,n;
	int a[105],b[105];
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		for(int i=1;i<=n;i++)scanf("%d",&a[i]);
		for(int i=1;i<=n;i++)scanf("%d",&b[i]);
		sort(a+1,a+n+1);sort(b+1,b+n+1);
		for(int i=1;i<=n;i++)printf("%d ",a[i]);
		printf("\n");
		for(int i=1;i<=n;i++)printf("%d ",b[i]);
		printf("\n");
	}
	return 0;
}


B. Kuroni and Simple Strings
题意
给定一个仅由“(”和“)”组成的字符串,定义一个括号序列为简单序列当且仅当:

  • 这个序列长为n,n为偶数
  • 这个序列前n/2项都为“(”,后n/2项都为“)”
    允许执行的操作是从字符串中选定一个子序列满足简单序列的条件并删除这个序列中所有的符号,问最少多少次删除后可以使得原字符串中不存在简单序列。输出最少删除次数以及每次删掉的元素数和元素下标。

题解
显然最多只要删除1次。从左往右扫,记录每个位置及其之前(的数量,从后往前扫,记录每个位置及其之后)的数量,再对每个位置枚举一次,求当前位置及之前(数量以及当前位置及其之后)数量的较小值,最后记录所有位置中该较小值的最大值,设其为x,依次输出前x个(的位置以及最后x个)的位置即可。
(正确性证明待补)

AC代码

#include
#include
#include
#include
#include
#include
#define MOD 1000000007
#include
using namespace std;
char s[10005];
int cot1[10005],cot2[10005];
int main()
{
	scanf("%s",s+1);
	int i;
	for(i=1;s[i];i++)
	{
		cot1[i]=cot1[i-1]+(s[i]=='(');
	}
	i--;
	for(;i;i--)
	{
		cot2[i]=cot2[i+1]+(s[i]==')');
	}
	int k=0;
	for(i=1;s[i];i++)
	{
		k=max(k,min(cot1[i],cot2[i]));
	}
	int len=i-1;
	if(k==0)
	{
		printf("0");
	}else
	{
		printf("1\n");
		printf("%d\n",2*k);
		int temp=k;
		for(i=1;temp&&s[i];i++)
		if(s[i]=='(')printf("%d ",i),temp--;
		temp=k;
		stack<int>sta;
		for(i=len;i&&temp;i--)
		{
			if(s[i]==')')sta.push(i),temp--;
		}
		while(!sta.empty())
		{
			printf("%d ",sta.top());sta.pop();
		}
	}
	return 0;
}

C. Kuroni and Impossible Calculation
题意
给定n,m,求一个长为n的数组a[]中 ∏ 1 ≤ i < j ≤ n ∣ a i − a j ∣ ∏_{1≤i1i<jnaiaj模m的值,其中 2 ≤ n ≤ 2 ⋅ 1 0 5 , 1 ≤ m ≤ 1000 2≤n≤2⋅10^5, 1≤m≤1000 2n2105,1m1000

题解
n>m时由抽屉原理知答案必为0。
n<=m时直接暴力算。

AC代码

#include
#include
#include
#include
#include
#include
#define MOD 1000000007
using namespace std;
long long ans[1005];
long long n,m;
int main()
{
	scanf("%I64d%I64d",&n,&m);
	if(n>m)printf("0");
	else
	{
		for(long long i=1;i<=n;i++)scanf("%I64d",&ans[i]);
		long long finalans=1;
		for(long long i=1;i<n;i++)
		for(long long j=i+1;j<=n;j++)
		{
			finalans*=(abs(ans[i]-ans[j])%m);
			finalans%=m;
		}
		printf("%I64d",finalans);
	}
	return 0;
}

D. Kuroni and the Celebration
题意
这是个交互题,给定一个n,一棵n个结点树的n-1条边,允许最多进行n/2(向下取整)次询问,每次询问可以得知两个点的LCA,目标是找到这棵树的树根。
题解
(其实感觉挺乱搞的)每次搜树的直径,然后询问直径两个端点的LCA,然后将直径上LCA两边的点及它们的子树全部删除,重复直到剩下一个点。
(正确性证明待补)

AC代码

#include
#include
#include
#include
#include
#include
#define MOD 1000000007
#define N 10005
using namespace std;
int p[N],nxt[N],he[N],f[N],depth[N];
int cot,que_cot,ans,n,n_2;
int que[1005];
int flag[1005];
void addedge(int from,int to)
{
	cot++;p[cot]=to;nxt[cot]=he[from];he[from]=cot;return;
}
void clearflag()
{
	for(int i=1;i<=n;i++)if(flag[i]>0)flag[i]=0,depth[i]=0;return;
}
void dfs(int now)
{
	flag[now]=1;
	for(int i=he[now];i;i=nxt[i])
	if(flag[p[i]]==0)
	{
		f[p[i]]=now;
		depth[p[i]]=depth[now]+1;
		dfs(p[i]);
	}
	return;
}
void findway()
{
	clearflag();
	dfs(ans);
	int max=0,pos=0;
	for(int i=1;i<=n;i++)
	if(flag[i]>0&&depth[i]>max){max=depth[i];pos=i;}
	clearflag();
	f[pos]=0;
	dfs(pos);
	max=0;
	que_cot=0;
	for(int i=1;i<=n;i++)
	if(flag[i]>0&&depth[i]>max){max=depth[i];pos=i;}
	for(int i=pos;i;i=f[i])
	{
		que_cot++;que[que_cot]=i;
	}
}
void ask()
{
	cout<<"? "<<que[1]<<' '<<que[que_cot]<<endl;
	cout.flush();
	cin>>ans;
}
void set_it(int now)
{
	flag[now]=-1;
	n_2--;
	for(int i=he[now];i;i=nxt[i])
	if(flag[p[i]]>=0)
	{
		set_it(p[i]);
	}
	return;
}
void search_and_set()
{
	int pos;
	for(int i=1;i<=que_cot;i++)if(que[i]==ans)pos=i;
	flag[ans]=-1;
	if(pos>1)set_it(que[pos-1]);
	if(pos<que_cot)set_it(que[pos+1]);
	flag[ans]=0;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<n;i++)
	{
		int x,y;
		cin>>x>>y;
		addedge(x,y);addedge(y,x);
	}
	ans=1;
	n_2=n;
	while(n_2!=1)
	{
		findway();
		ask();
		search_and_set();
	}
	cout<<"! "<<ans<<endl;
	cout.flush();
	return 0;
}

E. Kuroni and the Score Distribution
题意
给定n,m,要求构造一个长为n的数组a[]有 1 ≤ a 1 < a 2 < ⋯ < a n ≤ 1 0 9 1≤a_11a1<a2<<an109且满足恰好存在m个三元组 ( i , j , k ) (i,j,k) i,j,k 1 ≤ i < j < k ≤ n 1≤i1i<j<kn a i + a j = a k a_i+a_j=a_k ai+aj=ak能构造则输出数组,否则输出-1。

题解
是个构造题,我没证明最大可构造的上限数所以没写出这题。看了tourist的代码之后大概懂了。
题解待补

AC代码

#include
#include
#include
#include
#include
#include
#define MOD 1000000007
const long long M=100000;
using namespace std;
long long n,m;
long long ans[10005],cot;
int main()
{
	scanf("%I64d%I64d",&n,&m);
	cot=n;
	for(long long i=1;i<=n;i++)ans[i]=i*2-1;
	long long mx=0;
	for(long long i=1;i<=n;i++)mx+=(i-1)/2;
	if(mx<m) printf("-1");
	else
	{
		for(cot=n+1;(cot-n-1)/2<m;cot++)
		{
			ans[cot]=(cot-n)*M;m-=(cot-n-1)/2;
		}
		long long now=cot-n;
		while((cot-n-1)/2>m)
		{
			m++;now+=2;
		}
		ans[cot]=now*M;
		for(long long i=cot-n+1;i<=cot;i++)
		{
			printf("%I64d ",ans[i]);
		}
	}
	return 0;
}

你可能感兴趣的:(CodeForces,题解(按比赛))