NOI模拟(5.10) BJOID1T1 二进制 (bzoj5294)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/scar_lyw/article/details/80287838

二进制

题目背景:

5.10 模拟 BJOI2018D1T1

分析:线段树

 

比较显然的可以看出来,如果对于一个子区间,区间中的1的个数为偶数,显然是可行的,那么考虑奇数个1的情况,显然,如果只有11,那么无论如何都是不行的,而如果是3个及以上,那么我们只管三个就可以了,其他的可以像偶数一样处理,我们可以发现,2的整次幂模3的余数是1, 2, 1, 2,偶数个就是采取一个奇次幂 + 一个偶次幂,而多出来的三个,只能选择三个奇次幂或三个偶次幂,这样就是最优的了,所以说,对于由大于等于3的奇数个1的区间,要包含至少两个0才可以满足条件,那么我们相当于要维护在一个区间里,满足某些条件的子区间个数,这个是经典的线段树维护问题,我们考虑记录三个数组,sum[4][3], lx[4][3], rx[4][3],分别表示区间中的总的方案数,包含左端点的方案数,包含右端点的方案数,而对于后面的二维数组,第一位表示包含1的个数,0/1/2/3分别表示01/11/2个及两个以上的偶数个1/3个及三个以上的奇数个1,第二位表示0的个数,0/1/2分别表示00/10/2个及两个以上个0。比如说sum[2][1]就是表示,当前区间中,包含有有大于等于2的偶数个1,并且有且仅有一个0的子区间的个数。rx[1][2]表示,当前区间中,包含右端点的子区间中,包含有11,至少两个0的子区间个数。在update的过程中合并一下就可以了,只不过常数非常大,具体细节详见代码,所以2.0s非常必要,复杂度O(nlogn)

 

Source:

 

/*
    created by scarlyw
*/
#include <cstdio>
#include <string>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <cmath>
#include <cctype>
#include <vector>
#include <set>
#include <queue>
#include <ctime>
#include <bitset>
  
inline char read() {
    static const int IN_LEN = 1024 * 1024;
    static char buf[IN_LEN], *s, *t;
    if (s == t) {
        t = (s = buf) + fread(buf, 1, IN_LEN, stdin);
        if (s == t) return -1;
    }
    return *s++;
}
  
///*
template<class T>
inline void R(T &x) {
    static char c;
    static bool iosig;
    for (c = read(), iosig = false; !isdigit(c); c = read()) {
        if (c == -1) return ;
        if (c == '-') iosig = true; 
    }
    for (x = 0; isdigit(c); c = read()) 
        x = ((x << 2) + x << 1) + (c ^ '0');
    if (iosig) x = -x;
}
//*/
 
const int OUT_LEN = 1024 * 1024;
char obuf[OUT_LEN];
char *oh = obuf;
inline void write_char(char c) {
    if (oh == obuf + OUT_LEN) fwrite(obuf, 1, OUT_LEN, stdout), oh = obuf;
    *oh++ = c;
}
 
 
template<class T>
inline void W(T x) {
    static int buf[30], cnt;
    if (x == 0) write_char('0');
    else {
        if (x < 0) write_char('-'), x = -x;
        for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 + 48;
        while (cnt) write_char(buf[cnt--]);
    }
}
 
inline void flush() {
    fwrite(obuf, 1, oh - obuf, stdout), oh = obuf;
}
  
/*
template<class T>
inline void R(T &x) {
    static char c;
    static bool iosig;
    for (c = getchar(), iosig = false; !isdigit(c); c = getchar())
        if (c == '-') iosig = true; 
    for (x = 0; isdigit(c); c = getchar()) 
        x = ((x << 2) + x << 1) + (c ^ '0');
    if (iosig) x = -x;
}
//*/
 
const int MAXN = 100000 + 10;
 
int n, m, x, l, r, type;
int a[MAXN];
 
inline int get1(int x) {
    return (x <= 1) ? x : (x % 2 + 2);
}
 
inline int get0(int x) {
    return (x <= 1) ? x : 2;
}
 
struct node {
    long long cnt[2];
    long long sum[4][3], lx[4][3], rx[4][3];
    /*
    00: 0个1, 没有0  /
    01: 0个1, 一个0  /
    02: 0个1, 大于等于两个0  /
    10: 1个1, 没有0
    11: 1个1, 一个0
    12: 1个1, 大于等于两个0
    20: 大于等于2的偶数个1, 没有0  /
    21: 大于等于2的偶数个1, 1个0  /
    22: 大于等于2的偶数个1, 大于等于两个0  /
    30: 大于等于3的奇数个1, 没有0
    31: 大于等于3的奇数个1, 1个0
    32: 大于等于3的奇数个1, 大于等于两个0  /
    */
 
    inline node operator + (const node &a) const {
        node ans, lc = *this, rc = a;
        ans.cnt[0] = lc.cnt[0] + rc.cnt[0];
        ans.cnt[1] = lc.cnt[1] + rc.cnt[1];
        for (int i = 0; i <= 3; ++i)
            for (int j = 0; j <= 2; ++j) {
                ans.sum[i][j] = lc.sum[i][j] + rc.sum[i][j];
                ans.lx[i][j] = lc.lx[i][j];
                ans.rx[i][j] = rc.rx[i][j];
            }
        for (int i1 = 0; i1 <= 3; ++i1)
            for (int i0 = 0; i0 <= 2; ++i0)
                if (lc.rx[i1][i0]) {
                    long long x = lc.rx[i1][i0];
                    for (int j1 = 0; j1 <= 3; ++j1)
                        for (int j0 = 0; j0 <= 2; ++j0)
                            if (rc.lx[j1][j0]) {
                                long long y = rc.lx[j1][j0];
                                ans.sum[get1(i1 + j1)][get0(i0 + j0)] += x * y;
                            }
                }
        int lc0 = lc.cnt[0], lc1 = lc.cnt[1];
        int rc0 = rc.cnt[0], rc1 = rc.cnt[1];
        for (int i = 0; i <= 3; ++i)
            for (int j = 0; j <= 2; ++j) {
                ans.lx[get1(lc1 + i)][get0(lc0 + j)] += rc.lx[i][j];
                ans.rx[get1(rc1 + i)][get0(rc0 + j)] += lc.rx[i][j];
            }
        return ans;
    }
 
} tree[MAXN << 2 | 1];
 
inline void update(int k) {
    tree[k] = tree[k << 1] + tree[k << 1 | 1];
}
 
inline void build(int k, int l, int r) {
    if (l == r) {
        int x = (a[l] == 1), y = (a[l] == 0);
        tree[k].cnt[0] = y, tree[k].cnt[1] = x;
        tree[k].sum[x][y] = tree[k].lx[x][y] = tree[k].rx[x][y] = 1;
        return ;   
    }
    int mid = l + r >> 1;
    build(k << 1, l, mid), build(k << 1 | 1, mid + 1, r), update(k);
}
 
inline void modify(int k, int l, int r, int pos) {
    if (l == r) {
        int x = tree[k].cnt[1], y = tree[k].cnt[0];
        tree[k].sum[x][y] = tree[k].lx[x][y] = tree[k].rx[x][y] = 0;
        std::swap(tree[k].cnt[0], tree[k].cnt[1]);
        tree[k].sum[y][x] = tree[k].lx[y][x] = tree[k].rx[y][x] = 1;
        return ;
    }
    int mid = l + r >> 1;
    if (pos <= mid) modify(k << 1, l, mid, pos);
    else modify(k << 1 | 1, mid + 1, r, pos);
    update(k);
}
 
inline node query(int k, int l, int r, int ql, int qr) {
    if (ql <= l && r <= qr) return tree[k];
    int mid = l + r >> 1;
    if (qr <= mid) return query(k << 1, l, mid, ql, qr);
    else if (ql > mid) return query(k << 1 | 1, mid + 1, r, ql, qr);
    else return query(k << 1, l, mid, ql, qr)
              + query(k << 1 | 1, mid + 1, r, ql, qr);
}
 
inline void solve() {
    R(n);
    for (int i = 1; i <= n; ++i) R(a[i]);
    R(m), build(1, 1, n);
    node ans;
    long long ret;
    while (m--) {
        R(type);
        if (type == 1) R(x), modify(1, 1, n, x);
        else {
            R(l), R(r), ans = query(1, 1, n, l, r), ret = 0;
            ret = ans.sum[0][0] + ans.sum[0][1] + ans.sum[0][2]
                + ans.sum[2][0] + ans.sum[2][1] + ans.sum[2][2]
                + ans.sum[3][2];
            W(ret), write_char('\n');
        }
    } 
}
 
int main() {
    // freopen("binary.in", "r", stdin);
    // freopen("binary.out", "w", stdout);
    solve();
    flush();
    return 0;
}
阅读更多

没有更多推荐了,返回首页