联赛模拟测试16

T2 简单的序列

众所周知,这又是一道卡特兰数的题,但是小编又挂了,这已经是小编第三次挂在卡特兰数上了,这是怎么回事呢?原来是小编有一种情况没有考虑到,小编判断s集合括号匹配是这么判断的

for(int i=1;i<=m;++i)
    if(s[i]=='(')k++;
    else k--;

然后没有考虑到 )))((( 这种鬼情况,这种情况如果这么判断就挂了,然后就挂得只有 \(10pts\) ,我是暴力枚举,效率???可能是\((n-m)^2log_2(n-m)\),但可能也不是,用 C++(NOI) + O2 就 T 成85,开 C++O2 就快了至少三倍(可能是我常数太大了

首先先判断出原序列有多少个括号未匹配

for (int i = 1; i <= m; ++i) {
    if (s[i] == '(')k++;
    else k--;
    stt = (stt < k ? stt : k);
}

stt 表示有多少个 ')' 未匹配 k-stt 就是多少个 '(' 未匹配,然后枚举左右序列 p 和 q 中左右括号的数量,计算卡特兰数,相乘,就是结果

$ Code$

#include <bits/stdc++.h>
using namespace std;
#define gc getchar()
const long long mod = 1e9 + 7;
int n, m, k, sn, sm, stt;
char s[1000000 + 10];
long long v[1000000 + 10];

inline long long ksm(long long x, long long y) {
    register long long ans = 1;
    while (y) {
	if (y & 1)ans = ans * x % mod;
	y >>= 1;
	x = x * x % mod;
    }
	return ans;
}

inline long long C(long long n, long long m) {
    if (m == 0)return 1ll;
    return v[n] * ksm(v[m] * v[n - m] % mod, mod - 2) % mod;
}

inline void solve() {
    register int sn = -stt, sm = k - stt, pp;
    register long long ans = 0;
    pp = (n - m - sn - sm) >> 1;
    sn += pp, sm += pp;
    for (register int i = -stt; i <= sn; ++i)
      for (register int j = 0; j <= i + stt && j <= pp; ++j)
	    ans = (ans + (C(i + j, i) - C(i + j, j - 1)) % mod * (C(sn + sm - i - j, sm - j) - C(sn + sm - i - j, min(sn - i, sm - j) - 1)) % mod + mod) % mod;
    printf("%lld\n", ans);
}

inline void Solve() {
    sn = (n - m - k) >> 1;
    sm = n - m - sn;
    register long long x = min(sn, sm), ans = 0;
    for (int i = 0; i <= x; ++i)
		for (int j = 0; j <= i; ++j)
		    ans = (ans + (C(i + k + j, i + k) - C(i + k + j, j - 1)) % mod * (C(n - m - j - i - k, sn - j) - C(n - m - j - i - k, sn - j + 1)) % mod) % mod;
    printf("%lld\n", ans);
}

int main() {
    freopen("bracket.in", "r", stdin);
    freopen("bracket.out", "w", stdout);
    scanf("%d %d %s", &n, &m, s + 1), v[0] = 1;
    if (n % 2 == 1)return puts("0"), 0;
    for (int i = 1; i <= 300000; ++i)v[i] = v[i - 1] * i % mod;
    for (int i = 1; i <= m; ++i) {
	if (s[i] == '(')k++;
	else k--;
	stt = (stt < k ? stt : k);
    }
    if (stt < 0)solve();
    else Solve();
    return 0;
}
posted @ 2020-10-14 14:34  goote~  阅读(142)  评论(4编辑  收藏  举报
Live2D