zoukankan      html  css  js  c++  java
  • CodeForces 380.C Sereja and Brackets

    题意

    一串括号序列,只由(和)组成,然后是m个提问,提问l和r区间内,最大的匹配匹配括号数。

    思路

    第一,贪心的思想,用最正常的方式去尽量匹配,详细点说就是,先找到所有的(),然后删除这些(),再找所有的()。用这种方式匹配出来的,就是最优的方案。

    第二,如果我们把所有的'('当成+1, ')'当成-1, 然后画成函数,那么,我们可以通过函数的图像,来得到得到,这段区间的长度(r-l),这段区间的最小值(min),这段区间没用的')'的数量(f(l)-min),这段区间没用的'('的数量(f(r)-f(l)+(f(l)-min)) 然后就得到解了。

    另外,区间查询最小值,用线段树就行。

    本解 最重要的地方,在于通过函数图像得到解。最难得的就是如果通过函数图像得到解,唉,谁知道呢= =……

    我的代码

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    #define N 1020000
    #define lson(A) ((A)<<1)
    #define rson(A) ((A)<<1|1)
    
    int top;
    
    char str[N];
    int sum[N];
    
    int tree[N<<2];
    
    void init(int root, int l, int r) {
        if (l == r) {
            tree[root] = sum[l];
            return;
        }
        int mid = (l+r)/2;
        init(lson(root), l, mid);
        init(rson(root), mid+1, r);
        tree[root] = min(tree[lson(root)], tree[rson(root)]);
    }
    
    int query(int root, int rl, int rr, int ql, int qr) {
        if (root == -1) exit(-1);
        //printf("%d, %d %d %d %d
    ", root, rl, rr, ql ,qr);
        if ((rl == ql && rr == qr) || rl==rr) {
            return tree[root];
        }
        int mid = (rl+rr)/2;
        if (mid < ql) return query(rson(root), mid+1, rr, ql, qr);
        if (qr <= mid) return query(lson(root), rl, mid, ql, qr);
        else if (ql <= mid && mid+1 <= qr) 
            return min( query(lson(root), rl, mid, ql, min(mid, qr))
                       ,query(rson(root), mid+1, rr, max(mid+1, ql), qr));
        else exit(-1);
    }
    
    int main() {
        scanf("%s", str);
        sum[0] = 0;
        int i;
        for (i = 0; str[i]; i++) {
            sum[i+1] = sum[i] + (str[i] == '(' ? 1 : -1 );
        }
        int len = i;
        init(1, 0, len);
    
        int m;
        scanf("%d", &m);
        while (m--) {
            int l, r;
            scanf("%d%d", &l, &r);
            l--;
            int minnum = query(1, 0, len, l, r);
            int skipClose = sum[l] - minnum;
            int skipOpen = sum[r]-sum[l]+skipClose;
            //printf("(%d, %d,%d)
    ", minnum, skipClose, skipOpen);
            printf("%d
    ", r-l-skipClose-skipOpen);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    组合数学+结论——cf1359E
    【模拟】分类讨论大模拟+数论——cf1358F
    【思维】前缀和——cf1358E
    Android基础—— 自定义RecyclerView内部控件的监听器
    【思维】模拟+暴力——icpc nwrrc 2019 K
    分治模板
    树上问题&图论模板整理
    数据结构模板整理
    一些计数题
    Codeforces Round #567 (Div. 2)
  • 原文地址:https://www.cnblogs.com/shinecheng/p/3520013.html
Copyright © 2011-2022 走看看