题意
一串括号序列,只由(和)组成,然后是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; }