P5167 xtq的神笔

传送门

题解

倍增也好二分也好,果然复杂度只要和(log)插上关系就没我啥事了……

首先由一个显而易见然而我完全没有发现的结论,设(calc(l,r))表示区间([l,r])(or)起来加区间的(and)起来加区间的(gcd)起来(就是题目里说的那个乱七八糟的东西)的值,那么我们固定右端点(r),左端点逐渐座椅的过程中,(calc(l,r))的变化的次数为(O(log v)),其中(v)是所有格子的值域

证明:左移的时候,(or)(and)每次变化都会改变一个二进制位,最多改变(O(log v))次,而(gcd)因为每次都会变成自己的因子,值必然不超过之前的一半,所以总的变化次数也是(O(log v))

于是我们可以把之前的所有位置给分成(O(log v))段,其中每一段里面所有位置到当前位置的(or,and,gcd)都相等,这样可以用一个双向链表来维护,每次加入一个新位置的时候之前的区间不可能被拆分,只可能被合并。于是每一次加入之后合并,然后在这些所有的区间里找最优的就是了

//minamoto
#include<bits/stdc++.h>
#define R register
#define ll long long
#define fp(i,a,b) for(R int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(R int i=a,I=b-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
    R int res,f=1;R char ch;
    while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
    for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
    return res*f;
}
char sr[1<<21],z[20];int C=-1,Z=0;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
void print(R int x){
    if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;
    while(z[++Z]=x%10+48,x/=10);
    while(sr[++C]=z[Z],--Z);sr[++C]='
';
}
const int N=3e5+5,L=19;
int Log[N],a[N],st1[N][L],st2[N][L],st3[N][L];
struct node{ll v1,v2,v3,f;}p[N],res;int las[N],nxt[N],h,t,tot;ll f[N];
int n,k;
int gcd(int x,int y){return y?gcd(y,x%y):x;}
void ins(const node &b){
	p[++tot]=b,nxt[t]=tot,las[tot]=t;
	t=tot,nxt[tot]=-1;
}
void del(R int pos){
	nxt[las[pos]]=nxt[pos];
	pos==t?t=las[pos]:las[nxt[pos]]=las[pos];
}
int query_or(R int l,R int r){
	int k=Log[r-l+1];
	return st1[l][k]|st1[r-(1<<k)+1][k];
}
int query_and(R int l,R int r){
	int k=Log[r-l+1];
	return st2[l][k]&st2[r-(1<<k)+1][k];
}
int query_gcd(R int l,R int r){
	int k=Log[r-l+1];
	return gcd(st3[l][k],st3[r-(1<<k)+1][k]);
}
void clr(){
	tot=h=t=0;
	memset(nxt,0,sizeof(nxt)),memset(las,0,sizeof(las));
	memset(f,0xef,sizeof(f)),nxt[0]=-1;
}
int main(){
//	freopen("testdata.in","r",stdin);
	int T=read();fp(i,2,N-5)Log[i]=Log[i>>1]+1;
	while(T--){
		clr();
		n=read(),k=read();
		fp(i,1,n)st1[i][0]=st2[i][0]=st3[i][0]=a[i]=read();
		fp(i,1,k)f[i-1]=read();
		for(R int j=1;(1<<j)<=n;++j)fp(i,1,n-(1<<j)+1){
			st1[i][j]=st1[i][j-1]|st1[i+(1<<j-1)][j-1];
			st2[i][j]=st2[i][j-1]&st2[i+(1<<j-1)][j-1];
			st3[i][j]=gcd(st3[i][j-1],st3[i+(1<<j-1)][j-1]);
		}
		fp(i,k,n){
			int pos=nxt[h];
			while(pos>=0){
				p[pos].v1|=a[i],p[pos].v2&=a[i],p[pos].v3=gcd(p[pos].v3,a[i]);
				pos=nxt[pos];
			}res={query_or(i-k+1,i),query_and(i-k+1,i),query_gcd(i-k+1,i),f[i-k]};
			ins(res),pos=nxt[h];
			while(pos>=0&&nxt[pos]>=0){
				if(p[pos].v1==p[nxt[pos]].v1&&
					p[pos].v2==p[nxt[pos]].v2&&
					p[pos].v3==p[nxt[pos]].v3)
						cmax(p[pos].f,p[nxt[pos]].f),del(nxt[pos]);
				pos=nxt[pos];
			}pos=nxt[h];
			while(pos>=0)cmax(f[i],p[pos].v1+p[pos].v2+p[pos].v3+p[pos].f),pos=nxt[pos];
		}printf("%lld
",f[n]);
	}return 0;
}
原文地址:https://www.cnblogs.com/bztMinamoto/p/10206107.html