zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    poj 2528 Mayor's posters (线段树+离散化)
    poj 1201 Intervals (差分约束)
    hdu 4109 Instrction Arrangement (差分约束)
    poj 1195 Mobile phones (二维 树状数组)
    poj 2983 Is the Information Reliable? (差分约束)
    树状数组 讲解
    poj 2828 Buy Tickets (线段树)
    hdu 1166 敌兵布阵 (树状数组)
    Ubuntu网络配置
    Button控制窗体变量(开关控制灯的状态)
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/10206107.html
Copyright © 2011-2022 走看看