zoukankan      html  css  js  c++  java
  • Codechef MGCHGYM Misha and Gym 容斥、背包、Splay

    VJ传送门

    简化题意:给定一个长度为(N)的数列,(Q)个操作:

    (1\,x\,a)、将数列中第(x)个元素改为(a)

    (2\,l\,r)、反转子序列([l,r])

    (3\,l\,r\,w)、询问区间([l,r])中是否存在若干个数和为(w),一个数只能取一次

    注意:在整个过程中,在数列中出现过的数的种数不会超过(K(K leq 10))


    注意到最后一个条件很奇怪……

    考虑询问实际上是:最开始给出不超过(10)个数(a_1,...,a_{10}),每一次给出(a_1,...,a_{10})分别最多能够取的次数,问是否能够取出若干使得和为(w);而前两个操作只是在改变这个能够取的最多次数。

    不妨更进一步想,试着求能够取的方案数……

    是不是想到了……

    HAOI2008 硬币购物

    那么我们可以直接按照硬币购物的方法去做

    先用(a_1)(a_{10})跑完全背包,对于每一次询问进行容斥,强制令某一些数字超出使用次数并计算答案。那么每一次询问的复杂度是(2^{10})的。

    最后使用(Splay)维护一下前两个修改操作,题目就做完了。

    ​关于完全背包存不下那么多方案数的问题……直接模(10^9+7)

    #include<bits/stdc++.h>
    #define lch Tree[x].ch[0]
    #define rch Tree[x].ch[1]
    #define root Tree[0].ch[0]
    //This code is written by Itst
    using namespace std;
    
    inline int read(){
    	int a = 0;
    	char c = getchar();
    	bool f = 0;
    	while(!isdigit(c) && c != EOF){
    		if(c == '-')
    			f = 1;
    		c = getchar();
    	}
    	if(c == EOF)
    		exit(0);
    	while(isdigit(c)){
    		a = a * 10 + c - 48;
    		c = getchar();
    	}
    	return f ? -a : a;
    }
    
    const int MAXN = 1e5 + 10 , MOD = 1e9 + 7;
    int dp[MAXN] , dir[11] , *cnt , N , Q , cntN , cntL;
    map < int , int > lsh;
    struct node{
    	int ch[2] , sz , fa , val , sum[11];
    	bool mark;
    }Tree[MAXN];
    struct query{
    	int ind , a , b , c;
    }que[MAXN];
    
    inline int getL(int x){
    	if(!lsh.count(x)){
    		lsh[x] = ++cntL;
    		dir[cntL] = x;
    	}
    	return lsh[x];
    }
    
    inline bool son(int x){
    	return Tree[Tree[x].fa].ch[1] == x;
    }
    
    inline void pushup(int x){
    	for(int i = 1 ; i <= 10 ; ++i)
    		Tree[x].sum[i] = Tree[lch].sum[i] + Tree[rch].sum[i] + (Tree[x].val == i);
    	Tree[x].sz = Tree[lch].sz + Tree[rch].sz + 1;
    }
    
    inline void rotate(int x){
    	bool f = son(x);
    	int y = Tree[x].fa , z = Tree[y].fa , w = Tree[x].ch[f ^ 1];
    	Tree[x].fa = z;
    	Tree[z].ch[son(y)] = x;
    	Tree[x].ch[f ^ 1] = y;
    	Tree[y].fa = x;
    	Tree[y].ch[f] = w;
    	if(w)
    		Tree[w].fa = y;
    	pushup(y);
    }
    
    inline void Splay(int x , int tar){
    	while(Tree[x].fa != tar){
    		if(Tree[Tree[x].fa].fa != tar)
    			rotate(son(x) == son(Tree[x].fa) ? Tree[x].fa : x);
    		rotate(x);
    	}
    	pushup(x);
    }
    
    inline void mark(int x){
    	if(!x)
    		return;
    	swap(lch , rch);
    	Tree[x].mark ^= 1;
    }
    
    inline void pushdown(int x){
    	if(Tree[x].mark){
    		mark(lch);
    		mark(rch);
    		Tree[x].mark = 0;
    	}
    }
    
    void insert(int &x , int rk , int val , int fa){
    	if(!x){
    		x = ++cntN;
    		Tree[x].fa = fa;
    		Tree[x].sz = 1;
    		Tree[x].val = val;
    		Splay(x , 0);
    		return;
    	}
    	if(Tree[lch].sz >= rk)
    		insert(lch , rk , val , x);
    	else
    		insert(rch , rk - 1 - Tree[lch].sz , val , x);
    }
    
    void findKth(int x , int rk , int tar){
    	pushdown(x);
    	if(Tree[lch].sz == rk)
    		Splay(x , tar);
    	else
    		if(Tree[lch].sz > rk)
    			findKth(lch , rk , tar);
    		else
    			findKth(rch , rk - Tree[lch].sz - 1 , tar);
    }
    
    inline void modify(int x , int val){
    	findKth(root , x , 0);
    	--Tree[root].sum[Tree[root].val];
    	++Tree[root].sum[Tree[root].val = val];
    }
    
    inline void rev(int l , int r){
    	findKth(root , l - 1 , 0);
    	findKth(root , r + 1 , root);
    	mark(Tree[Tree[root].ch[1]].ch[0]);
    }
    
    inline void query(int l , int r){
    	findKth(root , l - 1 , 0);
    	findKth(root , r + 1 , root);
    	cnt = Tree[Tree[Tree[root].ch[1]].ch[0]].sum;
    }
    
    void init(){
    	dp[0] = 1;
    	for(int i = 1 ; i <= cntL ; ++i)
    		for(int j = dir[i] ; j <= 1e5 ; ++j)
    			dp[j] = (dp[j] + dp[j - dir[i]]) % MOD;
    }
    
    int dfs(int x , int sum , int flg){
    	if(sum < 0)
    		return 0;
    	if(x > cntL)
    		return flg * dp[sum];
    	return (dfs(x + 1 , sum , flg) + dfs(x + 1 , sum - (cnt[x] + 1) * dir[x] , flg * -1) + 1ll * MOD) % MOD;
    }
    
    int main(){
    #ifndef ONLINE_JUDGE
    	freopen("in","r",stdin);
    	freopen("out","w",stdout);
    #endif
    	N = read();
    	Q = read();
    	insert(root , 0 , 0 , 0);
    	for(int i = 1 ; i <= N ; ++i)
    		insert(root , i , getL(read()) , 0);
    	insert(root , N + 1 , 0 , 0);
    	for(int i = 1 ; i <= Q ; ++i){
    		que[i].ind = read();
    		que[i].a = read();
    		que[i].b = read();
    		if(que[i].ind == 3)
    			que[i].c = read();
    		if(que[i].ind == 1)
    			que[i].b = getL(que[i].b);
    	}
    	init();
    	for(int i = 1 ; i <= Q ; ++i)
    		switch(que[i].ind){
    		case 1:
    			modify(que[i].a , que[i].b);
    			break;
    		case 2:
    			rev(que[i].a , que[i].b);
    			break;
    		case 3:
    			query(que[i].a , que[i].b);
    			puts(dfs(1 , que[i].c , 1) ? "Yes" : "No");
    		}
    	return 0;
    }
    
  • 相关阅读:
    how to use http.Agent in node.js
    How Node.js Multiprocess Load Balancing Works
    Child Process
    What does cmd /C mean? [closed] 关于nodejs的子进程部分
    Net
    二进制与十六进制的关系
    POJ 1201 Intervals (差分约束系统)
    POJ 1201 Intervals (差分约束系统)
    差分约束系统
    差分约束系统
  • 原文地址:https://www.cnblogs.com/Itst/p/10327724.html
Copyright © 2011-2022 走看看