【Codeforces】 Codeforces Round #827 (Div. 4) A-G

279 阅读3分钟

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

A. Sum

题目大意

给定三个数字 a,b,ca , b , c,判断是否有两个数字相加等于第三个数字。

思路

直接判断每个数是否等于另外两个数之和。

代码

#include <bits/stdc++.h>
#define nn printf("NO\n")
#define yy printf("YES\n")
using namespace std;
int solve()
{
	int a,b,c;
	cin>>a>>b>>c;
	if (a==b+c||b==a+c||c==a+b) yy;
	else nn;
}
int main()
{
	int T=1;
	for (scanf("%d",&T);T--;) solve();
	return 0;
}

B. Increasing

题目大意

给你一个数组,问你是否能够通过重新排序保证数组严格单调递增,即重新排列数组之后 a1<a2<...<ana_1<a_2<...<a_n

思路

如果不存在两个数相等即输出 “YES”,否则输出 “NO”。

代码

#include <bits/stdc++.h>
using namespace std;
const int N=500001;
int f[N],x,y,z;
int n,m,k;
int solve()
{
	scanf("%d",&n);
	for (int i=1;i<=n;++i) cin>>f[i];
	sort(f+1,f+1+n);
	for (int i=2;i<=n;++i)
		if (f[i]==f[i-1]) return 0;
	return 1;
}
int main()
{
	int T=1;
	for (scanf("%d",&T);T--;)
                if (solve()) printf("YES\n");
                else printf("NO\n");
	return 0;
}

C. Stripes

题目大意

给一个 8×88\times 8 的方格,判断是否有横着的八个连续的 "R" 或者竖着的八个连续的 "B"。

思路

枚举行号和列号,暴力判断。

代码

#include <bits/stdc++.h>
using namespace std;
char a[11][11];
int checkr(int t)
{
	for (int i=1;i<=8;++i)
		if (a[t][i]!='R') return 0;
	return 1;
}
int checkc(int t)
{
	for (int i=1;i<=8;++i)
		if (a[i][t]!='B') return 0;
	return 1;
}
char solve()
{
	for (int i=1;i<=8;++i)
		for (int j=1;j<=8;++j) cin>>a[i][j];
	for (int i=1;i<=8;++i)
	{
		if (checkr(i)) return a[i][1];
		if (checkc(i)) return a[1][i];
	}
	return 'R';
}
int main()
{
	int T=1;
	for (scanf("%d",&T);T--;) cout<<solve()<<"\n";
	return 0;
}

D. Coprime

题目大意

给出含有 nn 个元素的数组 a1,a2,...,ana_1,a_2,...,a_n,在该数组中选择两个数 ai,aja_i,a_j 且二者互质,最大化 i+ji+j。无解输出 -1。

思路

由题目可知 max{ai}1000\max\{a_i\}\le 1000,我们可以先预处理出 1000 以内所有互质的数对,存入邻接矩阵。对于每个询问,只需先统计出值为 x 的数下标的最大值 v[x],然后枚举 i,j(1ij1000)i,j(1\le i\le j\le 1000),若 i,ji,j 互质,就用 v[i]+v[j] 更新答案。

代码

#include <bits/stdc++.h>
using namespace std;
const int N=500001;
int gcd(int x,int y){return y==0?x:gcd(y,x%y);}
int x,y,z;
int n,m,k,v[N];
int mp[2001][2001];
void solve()
{
	memset(v,0,sizeof(v));
	scanf("%d",&n);
	for (int i=1;i<=n;++i)
	{
		cin>>x;
		v[x]=i;
	}
	int ans=-1;
	for (int i=1;i<=2000;++i)
		for (int j=i;j<=2000;++j)
			if (v[i]&&v[j]&&mp[i][j]) ans=max(ans,v[i]+v[j]);
	printf("%d\n",ans);
}
int main()
{
	int T=1;
	for (int i=1;i<=2000;++i)
		for (int j=i+1;j<=2000;++j) mp[i][j]=(gcd(i,j)==1);
	mp[1][1]=1;

	for (scanf("%d",&T);T--;) solve();

	return 0;
}

E. Scuza

题目大意

一个含有 nn 个元素的数组 aia_i 表示第 ii 层楼梯和第 i1i − 1 层楼梯相差多高。

qq 个人,第 ii 个人腿长 kik i,当第 ajaj1a_j-a_{j-1}kik_i 大时,第 ii 个人就无法登上第 jj 层台阶,问你每个人最多能到达的高度。

思路

aia_i 做前缀和和前缀最大值,在前缀最大值数组里二分不超过 kik_i 的最靠右的位置 ll,输出 aa 数组中前 ll 个数的和。

代码

#include <bits/stdc++.h>
using namespace std;
const int N=500001;
int n,m,k,x;
int a[N],tot;
long long sum[N],maxx[N];
int solve()
{
	scanf("%d",&n);
	scanf("%d",&m);
	tot=0;
	for (int i=1;i<=n;++i)
	{
		scanf("%d",&a[i]);
		if (a[i]>maxx[tot])
		{
			maxx[++tot]=a[i];
			sum[tot]=sum[tot-1]+a[i];
		}
		else sum[tot]+=a[i];
	}
	int l,r,mid;
	while (m--)
	{
		scanf("%d",&x);
		l=0;
		r=tot;
		while (l!=r)
		{
			mid=l+r+1>>1;
			if (x>=maxx[mid]) l=mid;
			else r=mid-1;
		}
		printf("%lld ",sum[l]);
	}
	printf("\n");
}
int main()
{
	int T=1;
	for (scanf("%d",&T);T--;) solve();
	return 0;
}

F. Smaller

题目大意

给你一个字符串 ss 和 tt,最开始它们都等于 a 。每次给定一个操作会在 ss 或者 tt 的后面加一些字符,问你每次操作以后是否可以通过重新排序使得 ss 的字典序小于 tt

思路

观察发现:

  • tt 里有大于 a 的字符输出 "yes"
  • 否则 ss 里有大于 a 的字符输出 "no"
  • 否则比较长度

赛中被hack了QAQ

忘开 long long 见祖宗(

代码

#include <bits/stdc++.h>
#define nn printf("NO\n")
#define yy printf("YES\n")
#define nnn printf("No\n")
#define yyy printf("Yes\n")
using namespace std;
int x,y,z;
int n,m,k;
char a[500001];
int solve()
{
	int opt;
	long long t;
	scanf("%d",&k);
	int flag[2]={0,0};
	long long cnt[2]={1,1};
	while (k--)
	{
		cin>>opt>>t>>a+1;
		opt--;
		cnt[opt]+=t*strlen(a+1);
		for (int i=strlen(a+1);i&&!flag[opt];--i)
			if (a[i]>'a') flag[opt]=1;
		if (flag[1]) yy;
		else if (flag[0]) nn;
		else if (cnt[0]<cnt[1]) yy;
		else nn;
	}
}
int main()
{
	int T=1;
	for (scanf("%d",&T);T--;) solve();
	return 0;
}

G. Orray

题目大意

重新排列一个数组,使其前缀或数组的字典序尽量大。

思路

假设前 ii 个元素的前缀或最大值为 xx,考虑第 i+1i+1 个位置应该放未被使用过的元素剔除 xx 中为 1 的位置的影响后的最大值。即 maxai未被使用过{ai&(x)}\max_{a_i未被使用过}\{a_i\&(\sim x) \}

由于所有数字不超过 1000000000,则二进制表示不超过 30 位。每次有效的或运算会让某个二进制位由 0 变 1,则有效操作不超过30次。无效操作中数字的顺序不印象答案,可以随意输出。

代码

#include <bits/stdc++.h>
#define nn printf("NO\n")
#define yy printf("YES\n")
#define nnn printf("No\n")
#define yyy printf("Yes\n")
using namespace std;
using LL=long long;
typedef pair<int,int> PII;
const int N=500001;
const LL mod=1000000007;
//const LL mod=998244353;
vector<int> e[N];
int f[N],x,y,z;
int n,m,k;
void bcjInit() {for (int i=1;i<=n;++i) f[i]=i;}
int find(int x) {return f[x]==x?x:f[x]=find(f[x]);}
LL gcd(LL x,LL y) {return y==0?x:gcd(y,x%y);}
struct asdf{
	int val,otpt;
}a[N];
int cmp(asdf a,asdf b)
{
	return a.val<b.val;
}
int solve()
{
	scanf("%d",&n);
	for (int i=1;i<=n;++i) scanf("%d",&a[i].otpt),a[i].val=a[i].otpt;
	x=0;
	sort(a+1,a+1+n,cmp);
	for (int i=29;i>=0&&n;--i)
	{
		if (!(a[n].val&(1<<i))) continue;
		printf("%d ",a[n].otpt);
		x|=a[n].otpt;
		for (int j=1;j<n;++j)
			a[j].val&=(~a[n].otpt);
		n--;
		sort(a+1,a+1+n,cmp);
	}
	for (int i=1;i<=n;++i) printf("%d ",a[i].otpt);
	printf("\n");
}
int main()
{
	int T=1;

	for (scanf("%d",&T);T--;) solve();

	return 0;
}