Codeforces Round 882 题解

Codeforces Round 882 (Div. 2)

A. The Man who became a God

标签

greedy sortings

思路

  1. \(A\)\(|a_{i}-a_{i+1}|\) 的前 \(k-1\) 大之和,则答案即为\((\sum\limits_{1}^{n-1}|a_{i}-a_{i+1}|)-A\)
  2. 时间复杂度为 \(\mathcal O(tn\log n)\)

代码

点击查看代码
#include <bits/stdc++.h>
#define ll long long
#define ld long double
#define ull unsigned long long
using namespace std;
const int maxn=110;
int t,n,k,a[maxn],ans=0;
bool cmp(int a,int b) {return a>b;}
int main ()
{
	scanf("%d",&t);
	while(t--)
	{
		ans=0;
		scanf("%d%d",&n,&k);
		int x,y; scanf("%d",&x);
		for(int i=1;i<n;i++)
		{
			scanf("%d",&y);
			a[i]=abs(y-x),x=y;
		}
		sort(a+1,a+n,cmp);
		for(int i=k;i<n;i++)
			ans+=a[i];
		printf("%d\n",ans);
	}	 
	return 0;
}

B. Hamon Odyssey

标签

bitmasks greedy two pointers

思路

  1. 分析样例易得,可将 \(a_{l,\dots,r}\) 分为 \(a_{l,\dots,k}\)\(a_{k+1,\dots,r}\) 两部分的条件是:\(a_{l,\dots,k}\)\(a_{k+1,\dots,r}\) 的按位与和全为 \(0\)。又 \(0\&x=0,\forall x\in N\),故为了尽可能多的分组,根据贪心的思想,我们采取当 \(a_{l,\dots,r}\) 的按位与和恰恰\(0\) 便分为一组的策略。特别地,若按上述策略,使得最后剩下的数的按位与和不为 \(0\),则将这些数与上一组合并;若遍历完 \(a\) 后,分组数依为 \(0\),说明 \(a_{1,\dots,n}\) 的按位与和为 \(0\),此时最多分组数为 \(1\)
  2. 时间复杂度为 \(\mathcal O(\sum n)\)

代码

点击查看代码
#include <bits/stdc++.h>
#define ll long long
#define ld long double
#define ull unsigned long long
using namespace std;
const int maxn=2e5+100;
int t,n,a,ans,cur=-1; 
int main ()
{
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		cur=-1,ans=0;
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&a);
			if(cur==-1) cur=a;
			else cur&=a;
			if(cur==0) ans++,cur=-1;
		}
		if(ans==0) ans++;
		printf("%d\n",ans); 
	}
	return 0;
}

收获

  1. 双指针学习笔记

C. Vampiric Powers, anyone?

标签

bitmasks brute force

思路

  1. 考虑通过操作可得到的数的集合是什么样的。首先,由于 \(a^a=0\),故通过操作得到的数一定是 \(a\) 序列中若干个数的异或和,即 \(a_{i_1}\operatorname{xor}a_{i_2}\dots \operatorname{xor}a_{i_k}\)。然后,考虑 \(i_1,i_2,\dots,i_l\) 是否连续,可证明一定连续
  2. 证明 \(i_1,\dots,i_l\) 连续。设第 \(k\) 次操作得到的数为 \(a_{k+n}=a_{k+n-1}\operatorname{xor}a_{k+n-2}\dots\operatorname{xor}a_{k+n-p_1}\),第 \(k+1\) 次操作要得到的数为 \(a_{k+1+n}=a_{k+n}\operatorname{xor}a_{k+n-1}\dots\operatorname{xor}a_{k+n+1-p_2}\);则将 \(a_{k+n}\) 代入 \(a_{k+n+1}\) 得,\(a_{k+n+1}=a_{l_1}\operatorname{xor}a_{l_1-1}\dots\operatorname a_{l_1-p_3}\),其中 \(l_1<k+n\)。若 \(l_1>n\),则将 \(a_{l_1}\) 代入 \(a_{k+n}\) 中,以此类推,最终可得,\(a_{k+n}=a_{i_{1}}\operatorname{xor}a_{i_2}\dots\operatorname{xor}a_{i_l}\),根据前文可知,\(i_1,i_2,\dots,i_l\) 一定连续。故新生成的数一定是序列 \(a\) 的某一连续子列的异或和
  3. 思考如何得到所有的异或和。比较好想的思路,用前缀和优化暴力统计,时间复杂度为 \(\mathcal O(n^2)\),不可取。注意到异或为不进位加法以及元素最大值小于 \(2^8\),故可以运用代码中的方法,不再赘述。
  4. 时间复杂度为 \(\mathcal O(2^8n)\)

代码

点击查看代码
#include <bits/stdc++.h>
#define ll long long
#define ld long double
#define ull unsigned long long
using namespace std;
const int maxn=1e5+100;
int t,n,b[maxn],a,cur,ans;
int main ()
{
	int max_value=1<<8;
	scanf("%d",&t);
	while(t--)
	{
		cur=0,ans=0;
		scanf("%d",&n);
		for(int i=0;i<max_value;i++)
			b[i]=0;
		b[0]=1;
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&a);
			cur^=a;
			for(int j=0;j<max_value;j++)
				if(b[j]) ans=max(ans,cur^j);
			b[cur]=1;
		}
		printf("%d\n",ans);
	}
	return 0;
}

收获

  1. 在值域较小时统计区间某种和的一种方法。
posted @ 2023-07-10 10:18  shyiaw  阅读(37)  评论(0)    收藏  举报