Achen毒瘤模拟赛T3——小清新最优化
题意:给出n个序列,每个序列为二元组,其中代表:
(0,x) 对于一个数a,将它变成a&x
(1,x) 对于一个数b,将它变成a|x
给出q次询问,每次给出l,r,L,R,求出选定L~R区间中任意一数经过l~r的序列操作后最大结果
做法:看见题目,我们不难分析,无论如何进行位运算,只有|1和&0是会对原来的结果造成影响的,相当于进行复制操作。针对于此,我们可以对每一位做一个前缀的预处理,将每个序列之前的每一位操作所 有用的最后一个点算出来。而贪心策略很显然是从高位到低位进行贪心。从高位到低位扫下来,当遇到第一个当前位满足L<R的位时,就判断当前位是否会因为操作而改变值,如果不会,因为当前值不会改变,所以结果的当前位可设为1(最大),然后对后面的位进行扫描,如果下一位结果固定就该等于什么是什么,没有固定算一下当前位为1是否会大于R,不会就讲当前位设为1;如果会,就从当前位扫下去,该等于什么就等于什么。
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<set> #include<queue> #include<ctime> #define MAXN 200005 #define ll long long #define maxn 15 #define maxs 1000005 #define inf 1e9 #define eps 1e-9 using namespace std; inline char gc() { static char now[1<<16],*S,*T; if (T==S) { T=(S=now)+fread(now,1,1<<16,stdin); if (T==S) return EOF; } return *S++; } inline ll readlong() { ll x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-')f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x*=10; x+=ch-'0'; ch=getchar(); } return x*f; } inline int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-')f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x*=10; x+=ch-'0'; ch=getchar(); } return x*f; } void putint(long long t) { int ans[40]= {0}; for(; t; t/=10)ans[++ans[0]]=t%10; for(; ans[0]; ans[0]--)putchar('0'+ans[ans[0]]); putchar('\n'); } const int N=1000005; int f[35][N]; int num[N]; int trans[35]; int n; int main(){ n=read(); for(int i=1;i<=n;i++){ int op=read(); num[i]=read(); for(int j=0;j<=30;j++){ f[j][i]=((num[i]>>j&1)^op)?f[j][i-1]:i; } } int q=read(); while(q--){ int l=read(); int r=read(); int L=read(); int R=read(); for(int k=0;k<=30;k++){ trans[k]=(f[k][r]>=l)?(num[f[k][r]]>>k&1):-1; } int ans=0; int res=0; for(int k=30;k>=0;k--){ if((L>>k&1)<(R>>k&1)){ if(trans[k]==-1){ ans+=1<<k; res+=1<<k; for(int d=k-1;d>=0;d--){ if(trans[d]==1){ ans+=1<<d; } else if(trans[d]==-1&&res+(1<<d)<=R){ ans+=1<<d; res+=1<<d; } } } else{ for(int d=k;d>=0;d--){ if(trans[d]){ ans+=1<<d; } } } break; } res+=R&(1<<k); if(trans[k]==-1){ ans+=R&(1<<k); } if(trans[k]==1){ ans+=1<<k; } } printf("%d\n",ans); } return 0; }