zoukankan      html  css  js  c++  java
  • [JZOJ3339]【NOI2013模拟】wyl8899和法法塔的游戏

    题目

    题目大意

    给你一个数列,每次给出(r,a,b),你要找到(lin [a,b])使得([l,r-1])的异或和最小,
    并且要修改(r)位置的数。


    思考历程

    当我看到这题的时候,已经没有什么时间了……
    这题需要一点点的博弈基础(题目大意直接将它省掉了),不过还比较简单,就连我这样的博弈白痴都能会。
    搞出了之后就来了个最裸的暴力,交了上去。
    WA了……
    后面发现是答案为(-1)的时候我进行了修改操作……改了之后TLE63……


    水法

    说实在的这数据真的太水了,也是大把大把的人用暴力过去了。
    首先暴力方法加一点点优化就能过了(我在打正解的时候打了个暴力对照一下,将这个暴力交上去,AC……)
    接下来介绍一下LYL的分类讨论大法:
    有两种暴力方式,一种是直接暴力,一种是求前缀和暴力。
    LYL在程序中计算了两种暴力的时间,哪种暴力更优秀就使用哪种暴力……
    然后轻轻松松地水过了这题……


    正解

    正解的做法看起来比暴力复杂多了,是分块套(Trie)
    其实也很简单。先前缀和一遍,于是问题就转化成了在([a-1,b-1]) 中找到某个数使得它异或(pre_{y-1})最小。
    对于每个块建个(Trie),如果询问整个块,就在(Trie)上面找。如果修改,就打个标记。
    对于散块直接拆掉,暴力重构。
    时间复杂度为(O(msqrt n *10)),比较优秀……
    然而跑不过暴力……


    总结

    using namespace std;
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <climits>
    #include <cassert>
    #define N 100010
    #define maxK 320
    int n,m,K;
    int st[N],pre[N];
    int r[maxK],bel[N];
    struct Node{
    	Node *c[2];
    } d[32000001];
    int cnt;
    Node *root[maxK];
    inline void insert(Node *t,int x){
    	for (int i=9;i>=0;--i){
    		if (!t->c[x>>i&1])
    			t->c[x>>i&1]=&d[++cnt];
    		t=t->c[x>>i&1];
    	}
    }
    int lazy[maxK];
    inline void reduce(int k){
    	for (int i=r[k-1]+1;i<=r[k];++i)
    		pre[i]^=lazy[k];
    	lazy[k]=0;
    }
    inline void rebuild(int k){
    	root[k]=&d[++cnt];
    	for (int i=r[k-1]+1;i<=r[k];++i)
    		insert(root[k],pre[i]);
    }
    inline int find_min(Node *t,int y){
    	int res=0;
    	for (int i=9;i>=0;--i)
    		if (t->c[y>>i&1])
    			t=t->c[y>>i&1];
    		else{
    			t=t->c[y>>i&1^1];
    			res+=1<<i;
    		}
    	return res;
    }
    inline int get(int x){return pre[x]^lazy[bel[x]];}
    inline int query(int y,int a,int b){
    	int res=INT_MAX,aa=bel[a],bb=bel[b];
    	if (aa==bb){
    		if (lazy[aa])
    			reduce(aa),rebuild(aa);
    		for (int i=a;i<=b && res;++i)
    			res=min(res,pre[i]^y);
    		return res;
    	}
    	if (lazy[aa])
    		reduce(aa),rebuild(aa);
    	if (lazy[bb])
    		reduce(bb),rebuild(bb);
    	for (int i=a;i<=r[aa] && res;++i)
    		res=min(res,pre[i]^y);
    	for (int i=r[bb-1]+1;i<=b && res;++i)
    		res=min(res,pre[i]^y);
    	for (int i=aa+1;i<=bb-1 && res;++i)
    		res=min(res,find_min(root[i],y^lazy[i]));
    	return res;
    }
    inline void change(int l,int c){
    	int ll=bel[l];
    	if (lazy[ll])
    		reduce(ll);
    	for (int i=l;i<=r[ll];++i)
    		pre[i]^=c;
    	rebuild(ll);
    	for (int i=ll+1;i<=m;++i)
    		lazy[i]^=c;
    }
    int main(){
    	scanf("%d",&n);
    	for (int i=1;i<=n;++i)
    		scanf("%d",&st[i]),pre[i]=pre[i-1]^st[i];
    	K=sqrt(n);
    	for (int i=1;i*K<=n;++i)
    		r[++m]=i*K;
    	if (n%K)
    		r[++m]=n;
    	for (int i=1;i<=m;++i){
    		root[i]=&d[++cnt];
    		for (int j=r[i-1]+1;j<=r[i];++j){
    			insert(root[i],pre[j]);
    			bel[j]=i;
    		}
    	}
    	int T;
    	scanf("%d",&T);
    	while (T--){
    		int y,a,b;
    		scanf("%d%d%d",&y,&a,&b);
    		int xo=query(get(y-1),a-1,b-1),v=get(y)^get(y-1);
    		if (xo<v){
    			printf("%d
    ",v-xo);
    			change(y,v^xo);
    		}
    		else
    			printf("-1
    ");
    	}
    	return 0;
    }
    

    总结

    做题的时候要试着BFS地来做题……这样就可以早点发现这题可做了……
    不好维护的东西可以考虑一下分块……

  • 相关阅读:
    从原理层面掌握@InitBinder的使用【享学Spring MVC】
    array详解
    forward_list详解
    list详解
    deque详解
    vector详讲(三)实例
    vector详讲(二)迭代器
    vector详讲(一)
    numeric_limits<>函数
    seek()和tell()在文件里转移
  • 原文地址:https://www.cnblogs.com/jz-597/p/11160975.html
Copyright © 2011-2022 走看看