题解 牛客练习赛45D
考点:链表?瞎搞
链接:https://ac.nowcoder.com/acm/contest/847/D
题意:数组,提供三个操作,全部数与、或上一个x,查询数组分成k份的最大k-or-and具体见原题。
思路:无聊正好看见有比赛。。寻思练练手。。结果敲了个水题就被这题卡住了。。下来写了很久才过。
首先考虑到实际上参与答案计算的只有一开始大于k的位,于是建一个链表(偷懒用了vector,毕竟只有31个数),在操作的过程中维护这个链表。答案分两部分计算,一部分是全都一样的,一部分是链表里的。在统计答案的时候看看是否是最新的,不是的就up一下(实际上最多up31次)。up的时候纯暴力,从高位到低位一步步尝试就行了。。实际复杂度高达O(n(logn)^3)。。但是还是水过去了,暴力check的地方应该可以优化一下。。
#include <bits/stdc++.h>
#define X first
#define Y second
#define PB push_back
#define LL long long
#define pii pair<int,int>
#define MEM(x,y) memset(x,y,sizeof(x))
#define bug(x) cout<<"debug "#x" is "<<x<<endl;
#define FIO ios::sync_with_stdio(false);
#define ALL(x) x.begin(),x.end()
using namespace std;
const int maxn=200007;
const int mod=1e9+7;
const LL inf=2e18;
int n,k,q,x,y,a[maxn];
bool bit[31][maxn];
int is[31],push_down=0,cnt[31],real_cnt[31];
vector<int> lis;
void or_update(int x,int y){
if(y==0)return;
auto it=find(ALL(lis),x);
if(is[x]==-1&&it!=lis.end()){
lis.erase(it);
push_down=0;
}
is[x]=1;
}
void and_update(int x,int y){
if(y==1)return;
auto it=find(ALL(lis),x);
if(is[x]==-1&&it!=lis.end()){
lis.erase(it);
push_down=0;
}
is[x]=0;
}
bool tmp[maxn];
bool check(const vector<int> &ck,int x){
int cnt=0,siz=0,nn=ck.size(),h=0;
int S[32]={0};
for(int i=1;i<=n;i++){
if(siz<nn){
for(int c:ck){
if(bit[c][i]==1&&S[c]==0) S[c]=1,siz++;
}
}
if(bit[x][i]==1)h=1;
if(siz==nn&&h==1){
cnt++,MEM(S,0),siz=0,h=0;
if(cnt>=k)return 1;
}
}
return cnt>=k;
}
void update(){
vector<int> ck;
MEM(cnt,0);
if(lis.size()>0)cnt[lis[0]]=1,ck.PB(lis[0]);
for(int j=1;j<lis.size();j++){
int y=lis[j];
if(check(ck,y))ck.PB(y),cnt[y]=1;
}
push_down=1;
}
LL get_ans(){
if(push_down==0)update();
LL ret=0;
for(int i=0;i<31;i++){
if(is[i]==-1&&cnt[i]==1){
ret+=(1LL<<i);
}
else if(is[i]==1){
ret+=(1LL<<i);
}
}
return ret;
}
int main(){
FIO;
MEM(is,-1);
cin>>n>>k;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++){
for(int j=0;j<=30;j++)
bit[j][i]=((a[i]>>j)&1),real_cnt[j]+=((a[i]>>j)&1);
}
for(int j=30;j>=0;j--)if(real_cnt[j]>=k)lis.PB(j);
cin>>q;
while(q--){
cin>>x;
if(x==1){
cin>>y;
for(int i=0;i<31;i++)or_update(i,((y>>i)&1));
}
else if(x==2){
cin>>y;
for(int i=0;i<31;i++)and_update(i,((y>>i)&1));
}
else{
cout<<get_ans()<<endl;
}
}
}
/**
2 1
11 30
1
3
**/