【Codeforces】Codeforces Round #826 (Div. 3) 赛中过题记录A-E

152 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 1 月更文挑战」的第13天,点击查看活动详情

A Compare T-Shirt Sizes

题意

比较衣服的大小。

S 前面的 X 越多尺码越小,L 前面的 X 越多尺码越大。

  • XXXS < XS
  • XXXL > XL
  • XL > M
  • XXL = XXL
  • XXXXXS < M
  • XL > XXXS

思路

后缀不同,S < M < L。

后缀相同比较字符串长度。

代码

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <string.h>
#include <queue>
using namespace std;
int n,m,k;
char a[101],b[101]; 
int solve()
{
	cin>>a+1;
	cin>>b+1;
	n=strlen(a+1);
	m=strlen(b+1);
	if (a[n]=='S'&&b[m]=='S')
		if (n==m) printf("=\n");
		else if (n>m) printf("<\n");
		else printf(">\n");
	if (a[n]=='S'&&b[m]=='M') printf("<\n");
	if (a[n]=='S'&&b[m]=='L') printf("<\n");
	
	if (a[n]=='M'&&b[m]=='S') printf(">\n");
	if (a[n]=='M'&&b[m]=='M') printf("=\n");
	if (a[n]=='M'&&b[m]=='L') printf("<\n");
	
	if (a[n]=='L'&&b[m]=='S') printf(">\n");
	if (a[n]=='L'&&b[m]=='M') printf(">\n");
	if (a[n]=='L'&&b[m]=='L')
		if (n==m) printf("=\n");
		else if (n>m) printf(">\n");
		else printf("<\n");
}
int main()
{
	int T;
	for (scanf("%d",&T);T--;) solve();
}

B Funny Permutation

题意

对给定的 n,构造一个长度为 n 排列,使得该排列不存在 pi=ip_i = i 的情况,并且 pip_i 的相邻位置至少存在一个值与其差的绝对值为1的。

思路

如果 n 是 3,无解。

否则方法很多,下面给出一种合法的构造:

  • 如果 n 是奇数,则输出 n1,n,1,2,3,...,n2n-1,n,1,2,3,...,n-2
  • 如果 n 是偶数,则输出 2,1,4,3,...,n,n12,1,4,3,...,n,n-1

代码

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <string.h>
#include <queue>
using namespace std;
const int N=500001;
const long long mod=1000000007;
int n,m,k;
int solve()
{
	
	scanf("%d",&n);
	if (n==3) return printf("-1\n"),0;
	if (n%2)
	{
		printf("%d %d ",n,n-1);
		for (int i=1;i<n-1;++i) printf("%d ",i);
		printf("\n");
		return 0;
	} 
	for (int i=1;i<=n;i+=2) printf("%d %d ",i+1,i);
	printf("\n");
	return 0;
}
int main()
{
	int T;
	for (scanf("%d",&T);T--;) solve();
}

C Minimize the Thickness

题意

给定一个长度为 n 的数组,求将该数组分为连续的若干个部分,使得每一部分内部的和相同。求分完后每一部分的长度的最大值最小是多少。

思路

接枚举数组和的因子,表示每一部分的和是多少。

对于每一种可能的因子,遍历数组判断是否合法,若合法则求出最长段的长度。

对所有合法的最长段长度取 min 即可。

代码

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <string.h>
#include <queue>
using namespace std;
const int N=500001;
const long long mod=1000000007;
int n,m,k;
int a[N],p[N],tot; 
int check(int x)
{
	int ans=0,cnt=0,sum=0;
	for (int i=1;i<=n;++i)
	{
		sum+=a[i];
		cnt++;
		ans=max(ans,cnt);
		if (sum==x)	sum=cnt=0;
		if (sum>x) return -1;
	}
	return ans;
}
int solve()
{
	tot=0;
	scanf("%d",&n);
	int sum=0,ans=n+1;
	for (int i=1;i<=n;++i) scanf("%d",&a[i]),sum+=a[i];
	for (int i=1;1ll*i*i<=sum;++i)
		if (sum%i==0)
		{
			p[++tot]=i;
			p[++tot]=sum/i;
		}
	for (int i=1;i<=tot;++i)
	{
		int t=check(p[i]);
		if (t!=-1) ans=min(ans,t);
	}
	if (ans>n) printf("-1\n");
	else printf("%d\n",ans);
	return 0;
}
int main()
{
	int T;
	for (scanf("%d",&T);T--;) solve();
}

D Masha and a Beautiful Tree

题意

给定一个完全二叉树,有 n 个叶子节点,叶子节点的权值是 1 到 n 的一个排列排列。

一次操作可以交换一个子树的两个儿子,求最小化交换的操作使得叶子节点上的权值递增。

思路

递归,函数 check(l,r,x,y) 表示将原数组下标从 l 到 r 的位置中的元素排列成值取 x 到 y 的有序数组的最小操作次数。

如果 ala_l 的值处于 x 到 (x+y)/2 之间,该节点不应该进行交换,则答案为 check(l,(l+r)/2,x,(x+y)/2)+check((l+r)/2+1,r,(x+y)/2+1,y)check(l,(l+r)/2,x,(x+y)/2)+check((l+r)/2+1,r,(x+y)/2+1,y)。即将序列前半段和后半段分别进行排序的操作次数之和。

如果 ala_l 的值处于 (x+y)/2+1 到 y 之间,该节点需要交换左右子树,则答案为 check(l,(l+r)/2,(x+y)/2+1,y)+check((l+r)/2+1,r,x,(x+y)/2)+1check(l,(l+r)/2,(x+y)/2+1,y)+check((l+r)/2+1,r,x,(x+y)/2)+1。即将序列前半段和后半段分别进行排序的操作次数之和再加上本次进行的操作。

若递归到叶子节点发现无法取得需要的权值,即 l=rl=ra[l]xa[l]\neq x,则说明该完全二叉树无法通过题目给出的操作完成排序,输出 -1。

树中每个节点都会被访问一次,节点数量为 2n-1,时间复杂度为 O(n)。

代码

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <string.h>
#include <queue>
using namespace std;
const int N=500001;
const long long mod=1000000007;
int n,m,k;
int a[N],flag;
int check(int l,int r,int x,int y)
{
	if (l==r&&a[l]!=x) flag=0;
	if (l==r) return 0;
	if (a[l]<=(x+y>>1)) return check(l,(l+r>>1),x,(x+y>>1))+check((l+r>>1)+1,r,(x+y>>1)+1,y);
	return check(l,(l+r>>1),(x+y>>1)+1,y)+check((l+r>>1)+1,r,x,(x+y>>1))+1;
}
int solve()
{
	scanf("%d",&n);
	for (int i=1;i<=n;++i) scanf("%d",&a[i]);
	flag=1;
	int t=check(1,n,1,n);
	if (flag) printf("%d\n",t);
	else printf("-1\n");
	return 0;
}
int main()
{
	int T;
	for (scanf("%d",&T);T--;) solve();
}

E Sending a Sequence Over the Network

题意

对于长度为 nn 的一串正整数 a1,a2,...,ana_1,a_2,...,a_n,下面两种写法都可以称为它的 network 表示:

  • n,a1,a2,...,ann,a_1,a_2,...,a_n
  • a1,a2,...,an,na_1,a_2,...,a_n,n

给定一个数字串 b,判断它是否能被划分成若干连续的段,其中每段都是一串正整数的 network 表示。

思路

动态规划,v[i] 表示前 i 个数是否存在合法划分。

遍历 b 数组,假设当前位置 b[i] 是长度,则:

  • b[i] 表示的序列在后面,如果前 i-1个数存在合法划分,则前 i+a[i] 个数存在合法划分。
  • b[i] 表示的序列在前面,如果前 i-a[i]-1 个数存在合法划分,则前 i 个数存在合法划分。

代码

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <string.h>
#include <queue>
using namespace std;
const int N=500001;
int n,m,k;
int a[N],v[N];
int solve()
{
	for (int i=1;i<=n;++i) v[i]=0;
	scanf("%d",&n);
	v[0]=1;
	for (int i=1;i<=n;++i)
	{
		scanf("%d",&a[i]);
		if (i-a[i]-1>=0&&v[i-a[i]-1]) v[i]=1;
		if (v[i-1]&&i+a[i]<=n) v[i+a[i]]=1;
	}
	return v[n];
	
}
int main()
{
	int T;
	for (scanf("%d",&T);T--;)
                if (solve()) printf("YES\n");
                else printf("NO\n");
}