• 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;
    }
    
  • 相关阅读:
    python 统计gitlab代码量
    whistle 模拟用户网络超时
    Node.js 快速转换 url 链接
    实用的 Git 命令
    前端常用 prettier 配置 + vetur 配置
    vue 项目 eslint + prettier 配置
    lodash 方法 debounce 防连点 防抖按钮点击
    npm 包实现自动登录 CICD 流程
    git push --follow-tags 命令
    小程序 iOS webview 中网页使用 iframe 无法滚动问题
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/10206107.html
Copyright © 2020-2023  润新知