Codeforces Round 882 题解
Codeforces Round 882 (Div. 2)
A. The Man who became a God
标签
greedy sortings
思路
- 记 \(A\) 为 \(|a_{i}-a_{i+1}|\) 的前 \(k-1\) 大之和,则答案即为\((\sum\limits_{1}^{n-1}|a_{i}-a_{i+1}|)-A\)。
- 时间复杂度为 \(\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
思路
- 分析样例易得,可将 \(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\)。
- 时间复杂度为 \(\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;
}
收获
C. Vampiric Powers, anyone?
标签
bitmasks brute force
思路
- 考虑通过操作可得到的数的集合是什么样的。首先,由于 \(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\) 是否连续,可证明一定连续。
- 证明 \(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\) 的某一连续子列的异或和。
- 思考如何得到所有的异或和。比较好想的思路,用前缀和优化暴力统计,时间复杂度为 \(\mathcal O(n^2)\),不可取。注意到异或为不进位加法以及元素最大值小于 \(2^8\),故可以运用代码中的方法,不再赘述。
- 时间复杂度为 \(\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;
}
收获
- 在值域较小时统计区间某种和的一种方法。

浙公网安备 33010602011771号