1. 程式人生 > >Codechef MGCHGYM Misha and Gym 容斥、背包、Splay

Codechef MGCHGYM Misha and Gym 容斥、背包、Splay

its insert 直接 stdout tchar const cas read init

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;
}

Codechef MGCHGYM Misha and Gym 容斥、背包、Splay