zoukankan      html  css  js  c++  java
  • NOI2019 SX 模拟赛 no.5

    Mas 的童年

    题目描述:不知道传送门有没有用?

    反正就是对于每个前缀序列求一个断点,使得断点左右两个区间的 分别的异或和 的和最大

    分析

    jzoj 原题?

    但是我 TM 代码没存账号也过期了啊!

    然后只能绞尽脑汁思考做法,然后在左边 bzt 大仙各种提示下终于打出了一个 n log n 的做法

    考虑暴力肯定非常可做于是我们来个暴力完事

    我们想想当前的前缀序列的异或和为 x 的情况下,我们考虑从高位到低位去使贡献最大化:

    那么假设当前处理的位置是 i :

    如果 x 的第 i 位为 0 ,并且能从前面找到某个断点使得左边右边两个区间的当前位都是 1 ,那这样肯定是最优的,我们给找寻的断点加上这个限制

    另外,我们考虑是从高位处理到低位的,我们在考虑 y 位的贡献时前面位的贡献必须已经最大化了,那么我们要在前面高位的限制下寻找新的断点,找到就增加答案并增加限制,找不到就拉倒什么也别干

    如果 x 的第 i 位为 1 ,那么怎么分都没关系,贡献都是 1 ,限制就比较小

    然后我们江当前的前缀作为一个断点,江它的所有真子集都变为 1 表示存在这样的断点

    但是这样的复杂度是 (n m) 的, m 就是 (a_i) 的数据范围(说白了就是 (n^2)

    那么怎么优化呢?

    我们考虑从断点更新方面无法优化了,那么考虑这个子集能不能预处理

    预处理的方法就是对于每种状态我们记录一下它最早可以达到的时间点,然后寻找的时候直接看当前限制状态记录的时间点是否在当前时间的前面,如果是的话就说明存在满足条件的断点

    这样做有什么优化到的地方么? 我们发现可以用高维前缀和传递信息,复杂度$ n ~log~ m $

    于是高维前缀和就弄掉

    //by Judge
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #define Rg register
    #define fp(i,a,b) for(Rg int i=(a),I=(b)+1;i<I;++i)
    #define fd(i,a,b) for(Rg int i=(a),I=(b)-1;i>I;--i)
    #define lowbit(x) (x&-x)
    #define ll long long
    using namespace std;
    const int M=2e6+3;
    #ifndef Judge
    #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
    #endif
    char buf[1<<21],*p1=buf,*p2=buf;
    inline bool cmin(int& a,int b){return a>b?a=b,1:0;}
    inline bool cmax(int& a,int b){return a<b?a=b,1:0;}
    inline int read(){ int x=0,f=1; char c=getchar();
    	for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    	for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f;
    } char sr[1<<21],z[20];int CCF=-1,Z;
    inline void Ot(){fwrite(sr,1,CCF+1,stdout),CCF=-1;}
    inline void print(int x,char chr=' '){
        if(CCF>1<<20)Ot();if(x<0)sr[++CCF]=45,x=-x;
        while(z[++Z]=x%10+48,x/=10);
        while(sr[++CCF]=z[Z],--Z);sr[++CCF]=chr;
    } int n,mx,a[M],pre[M],tmp;
    int main(){ n=read(),memset(pre,0x3f,sizeof pre);
    	fp(i,1,n) a[i]=read()^a[i-1]; fd(i,n,1) pre[a[i]]=i,cmax(mx,a[i]);
    	fd(i,mx,1) fp(j,0,20) if((i>>j)&1) cmin(pre[i^(1<<j)],pre[i]);
    	fp(i,1,n){ tmp=0;
    		fd(j,20,0) if(((a[i]>>j)&1)^1)
    			if(pre[tmp|(1<<j)]<=i) tmp|=1<<j;
    		print((a[i]^tmp)+tmp);
    	} return sr[CCF]='
    ',Ot(),0;
    }
    

    Z的家乡

    题目描述:不知道传送门有没有用?

    反正就是给你一棵树每次在树上加一个叶子,然后要你在每次加入的节点后 dfs
    序的最大字典序...(讲不大清楚?)

    然后就是一眼看出这玩意儿超级像 LCT 中的 access ,每次都把当前节点所在的链优先级提到最大了,但是不会做...

    没搞懂,抄了篇比较短的代码感觉还不错...就当是锻炼手速了!

    //by Judge
    #include<bits/stdc++.h>
    #define fp(i,a,b) for(register int i=(a),I=(b)+1;i<I;++i)
    using namespace std;
    const int mod=998244353;
    const int M=1e5+3;
    typedef int arr[M];
    #ifndef Judge
    #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
    #endif
    char buf[1<<21],*p1=buf,*p2=buf;
    inline int mul(int a,int b){return 1ll*a*b%mod;}
    inline int inc(int a,int b){return a+b>=mod?a+b-mod:a+b;}
    inline int read(){ int x=0,f=1; char c=getchar();
    	for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    	for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f;
    } char sr[1<<21],z[20];int CCF=-1,Z;
    inline void Ot(){fwrite(sr,1,CCF+1,stdout),CCF=-1;}
    inline void print(int x,char chr='
    '){
        if(CCF>1<<20)Ot();if(x<0)sr[++CCF]=45,x=-x;
        while(z[++Z]=x%10+48,x/=10);
        while(sr[++CCF]=z[Z],--Z);sr[++CCF]=chr;
    } int n,pw[M];
    struct data{ int siz,ans;
    	data operator +(data y)const{
    		return (data){siz+y.siz,inc(ans,mul(y.ans,pw[siz]))};
    	}
    };
    struct seg{ int l,r; data x; };
    namespace seg_T{ int x,tot,root[M],stk[M*20]; data y; seg t[M*20];
    	#define mid ((l+r)>>1)
    	#define lch t[rt].l
    	#define rch t[rt].r
    	inline int New(){return *stk?stk[(*stk)--]:++tot;}
    	inline void R(int& rt){t[rt].l=t[rt].r=0,t[rt].x=(data){0,0},stk[++*stk]=rt,rt=0;}
    	inline void add(int l,int r,int& rt){ if(!rt) rt=New(); if(l==r) return t[rt].x=y,void();
    		if(x<=mid) add(l,mid,lch); else add(mid+1,r,rch); t[rt].x=t[rch].x+t[lch].x;
    	}
    	inline void del(int l,int r,int& rt){ if(l==r) return R(rt);
    		if(x<=mid) del(l,mid,lch); else del(mid+1,r,rch);
    		t[rt].x=t[rch].x+t[lch].x; if(!t[rt].x.siz) R(rt);
    	}
    	inline void add(int rt,int _x,data _y){x=_x,y=_y,add(1,n,root[rt]);}
    	inline void del(int rt,int _x){x=_x,del(1,n,root[rt]);}
    	inline data get(int x){return t[root[x]].x;}
    } using namespace seg_T;
    struct LCT{ arr f,l,r,id; data t[M];
    	inline bool isroot(int x){return l[f[x]]^x&&r[f[x]]^x;}
    	inline void pushup(int x){ id[x]=r[x]?id[r[x]]:x,t[x]=t[r[x]]+get(x)+(data){1,x}+t[l[x]];}
    	inline void rotate(int x){ int y=f[x],z=f[y];
    		if(l[z]==y) l[z]=x; else if(r[z]==y) r[z]=x; f[x]=z,f[y]=x;
    		if(l[y]==x) f[l[y]=r[x]]=y,r[x]=y; else f[r[y]=l[x]]=y,l[x]=y;
    		pushup(y),pushup(x);
    	}
    	inline void splay(int x){
    		for(int y,z;!isroot(x);rotate(x))
    			if(y=f[x],z=f[y],!isroot(y))
    				rotate((l[z]==y)^(l[y]==x)?x:y);
    	}
    	inline void init(){fp(i,1,n) pushup(i);}
    	inline void link(int u,int v){ int p1,p2,x;
    		for(f[x=v]=u,p1=0;x;x=f[x]){ splay(x);
    			if(r[x]) add(x,id[r[x]],t[r[x]]);
    			if(r[x]=p1,p1&&p1^v) del(x,p2);
    			p1=x,p2=id[x],pushup(x);
    		} splay(v),print(t[v].ans);
    	}
    }T;
    int main(){ n=read(),pw[0]=1;
    	fp(i,1,n) pw[i]=mul(pw[i-1],257933);
    	T.init(); fp(i,2,n) T.link(read(),i);
    	return Ot(),0;
    }
    

    战棋游戏

    题目描述:不知道传送门有没有用?

    反正就是不可做

    分析

    NTT,不会,我只会打板子

    代码?算了吧...(比赛比完都没几个 A 的)

  • 相关阅读:
    MVC3的零散记录 EF常见的转换规则
    MVC3的零散记录 设置区域(Areas)后遭遇IE浏览器 jQuery未定义错误
    Visual Studio 2010 选中高亮插件 Highlight all occurrences of selected word
    asp.net mvc 在表单中输入html标记
    实验818 报数 (20 分)
    关于SQL SERVER中获取表的主键名
    MVC4的新增功能之前端优化
    winform中实现不重复创建窗体
    微盘产品分析(零):时代向前走了一步
    网络相册产品分析(一):十年需求变迁
  • 原文地址:https://www.cnblogs.com/Judge/p/10636341.html
Copyright © 2011-2022 走看看