Codeforces Round #840 (Div. 2) and Enigma 2022 - Cybros LNMIIT

好久都没写博客了,今天vp了第一场CF,纪念一下。

A

先任意固定某两个数为最大值或最小值,再对每一位考虑,把每个数都扫一遍,如果既有 \(1\) 又有 \(0\),那么我们总可以把 \(1\) 换给最大值,把 \(0\) 换给最小值。那么答案的这一位就是 \(1\),否则是 \(0\)

\(O(10n)\)

#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define mkp make_pair
using namespace std;
using ll=long long;
using pii=pair<int,int>;
using pll=pair<ll,ll>;
using ull=unsigned long long;
inline void read(int &x){
  char ch=getchar();
  int r=0,w=1;
  while(!isdigit(ch))w=ch=='-'?-1:1,ch=getchar();
  while(isdigit(ch))r=(r<<1)+(r<<3)+(ch^48),ch=getchar();
  x=r*w;
}
const int N=643;
int a[N];
void solve(){
  int n;read(n);
  for(int i=1;i<=n;i++)read(a[i]);
  int ans=0;
  for(int i=0;i<=10;i++){
    bool b1=0,b2=0;
    for(int j=1;j<=n;j++){
      if((a[j]>>i)&1)b1=1;
      else b2=1;
    }
    if(b1&b2)ans+=(1<<i);
  }
  printf("%d\n",ans);
}
int main(){
  int T;read(T);
  while(T--)solve();
  return 0;
}

B

似乎网上的方法都比我简单。。。

首先我们不关心怪兽的先后顺序,于是我们可以按怪兽的健康值排序,那么我们每次可以二分找到第一个大于 \(k\) 的位置 \(id\),那么它前面的都会被杀死,问题给到求 \([id,n]\) 的最小能力值,ST 表实现。

upd:后缀最小值只需要 \(O(n)\) 扫一遍,ST 表大材小用了。

\(O(n\log n)\)

#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define mkp make_pair
using namespace std;
using ll=long long;
using pii=pair<int,int>;
using pll=pair<ll,ll>;
using ull=unsigned long long;
inline void read(int &x){
  char ch=getchar();
  int r=0,w=1;
  while(!isdigit(ch))w=ch=='-'?-1:1,ch=getchar();
  while(isdigit(ch))r=(r<<1)+(r<<3)+(ch^48),ch=getchar();
  x=r*w;
}
const int N=1e5+7,inf=1e9+7;
struct monster{
  int h,p;
  bool operator<(const monster &b)const{
    return h<b.h;
  }
}a[N];
int f[N][18],lg[N],n,k;
void st(){
  for(int i=1;i<=n;i++)f[i][0]=a[i].p;
  for(int j=1;j<=17;j++)for(int i=1;i+(1<<(j-1))<=n;i++)
    f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]);
  lg[1]=0;lg[2]=1;
  for(int i=3;i<=n;i++)lg[i]=lg[i/2]+1;
}
int query(int l,int r){
  int t=lg[r-l+1];
  return min(f[l][t],f[r-(1<<t)+1][t]);
}
void solve(){
  read(n);read(k);
  for(int i=1;i<=n;i++)read(a[i].h);
  for(int i=1;i<=n;i++)read(a[i].p);
  sort(a+1,a+n+1);st();
  a[n+1].h=inf;
  int now=1,sum=0;//注意我们没有减健康值,要记所有k的和
  while(k>0){
    int t=upper_bound(a+now,a+n+2,monster{sum+k,0})-a;
    now=t;
    if(now>n)break;
    sum+=k;
    k-=query(now,n);
  }
  puts(now>n?"Yes":"No");
}
int main(){
  int T;read(T);
  while(T--)solve();
  return 0;
}

C

结论:记 \(mx\) 为整个序列的最大值,那么当 \(n\ge 4\) 时整个序列都能变成 \(mx\),答案为 \(mx\times n\)

证明:记 \(k\)\(mx\) 在序列中的位置。
显然如果对一个 \([l,r]\) 操作两次就可以使其全变成 \(0\),利用好这个性质。

\(k=1\) 时,操作:\([2,n]\times 2\)\([1,n]\)
\(k=2\) 时,操作:\([3,n]\times 2\)\([2,n]\)\([1,2]\times 2\)\([1,n]\)
\(3\le k \le n-2\) 时,操作:\([1,k-1]\times 2\)\([k+1,n]\times 2\)\([k,n]\)\([1,n]\)
\(k=n-1\) 时,操作:\([1,n-2]\times 2\)\([1,n-1]\)\([n-1,n]\times 2\)\([1,n]\)
\(k=n\) 时,操作:\([1,n-1]\times 2\)\([1,n]\)
证毕。

再次注意只针对于 \(n\ge 4\)\(n=2\)\(3\) 手模即可。

\(O(n)\)

#include<bits/stdc++.h>
#define int long long
#define fi first
#define se second
#define pb push_back
#define mkp make_pair
using namespace std;
using ll=long long;
using pii=pair<int,int>;
using pll=pair<ll,ll>;
using ull=unsigned long long;
inline void read(int &x){
  char ch=getchar();
  int r=0,w=1;
  while(!isdigit(ch))w=ch=='-'?-1:1,ch=getchar();
  while(isdigit(ch))r=(r<<1)+(r<<3)+(ch^48),ch=getchar();
  x=r*w;
}
const int N=2e5+7;
int a[N];
void solve(){
  int n,mx=0;read(n);
  for(int i=1;i<=n;i++)read(a[i]),mx=max(mx,a[i]);
  if(n>3)printf("%lld\n",n*mx);
  else if(n==2)printf("%lld\n",max(a[1]+a[2],2*abs(a[1]-a[2])));
  else if(n==3)printf("%lld\n",max(a[1]+a[2]+a[3],3*max({a[1],a[3],abs(a[1]-a[2]),abs(a[1]-a[3]),abs(a[2]-a[3])})));
}
main(){
  int T;read(T);
  while(T--)solve();
  return 0;
}

D 翻译没看懂,刚好要上网课,就没继续做了。

DE似乎不是很难,在我能力范围内,如果我记得就补。

posted @ 2022-12-23 15:28  Epoch_L  阅读(45)  评论(0编辑  收藏  举报