Deltix Round, Summer 2021 (open for everyone, rated, Div. 1 + Div. 2)C—D

C. Compressed Bracket Sequence

      一道比较有意思的括号匹配问题,可以发现括号的数量很多,有1e9 * 1000个,所以我们放弃将括号表示出来,考虑其他方法。观察可以发现这个n很小,只有1000,可以从n下手。

      可以想到 O ( n 2 ) O(n^2) O(n2)的暴力枚举起点和终点,然后计算当前起点和终点为答案贡献的合法括号数量(注意,我们统计的是包含当前起点和终点的合法括号)。

      注意到只有左括号作为起点才对答案有贡献,所以我们的起点只用枚举所有的奇数位就可以。

       首先我们把左端点(起点)位置的左括号数量设为begin,然后控制右端点(终点)向后走,途中遇到的未匹配的左括号数量为sum。如果遇到了右括号,那么我们首先判断sum的数量是否大于当前右括号的数量,如果大于等于,说明当前所有的右括号都与途中未匹配的左括号匹配了,无法与起点位置的左括号匹配;如果小于,说明当前位置的右括号除了与途中的左括号匹配之外,还有有一部分可以与起点位置的左括号匹配,对答案做贡献,设当前的右括号数量为p,这个贡献就是min(begin,p - sum);
      有一个需要注意的地方是:如果p > sum且sum != 0,那么答案需要加1。
     例如:(()()),右边的()除了自己会形成一个合法答案之外{这个自己形成的合法答案会在起点周到下标为4(下标从1开始)的位置上时才会计入答案},()()也是一个合法答案(即它会与前面已经匹配好的合法括号合并成一个新的合法括号)。

ACcode:

#include<bits/stdc++.h>
using namespace std;

const int N = 1e5 + 100;
typedef long long ll;
typedef pair<int, int> PII;

int a[N];

void solve() {
    int n;
    ll ans = 0;
    scanf("%d", &n);
    for(int i = 1; i <= n; ++ i) scanf("%d", &a[i]);
    for(int i = 1; i <= n; i += 2) {
        ll sum = 0, beg = a[i];
        for(int j = i + 1; j <= n; ++ j) {
            if(j & 1) sum += a[j];
            else {
                if(sum > a[j]) {
                    sum -= a[j];
                }
                else {
                    if(sum != 0) ans ++;
                    ans += min(beg, a[j] - sum);
                    beg -= a[j] - sum;
                    sum = 0;
                }
            }
            if(beg < 0) break; 
            //如果当前起点剩余未匹配的左括号数量小于0的话,说明以当前起点作为左端点的合法括号不可能存在,所以需要换一个起点。
           //如果当前起点剩余未匹配的左括号数量等于0的话,后面还有可能有新的合法括号与当前起点匹配完的括号组成一个新的合法括号,例如:()()(())。
        }
    }
    printf("%lld\n", ans);
}

int main() {
    #ifndef ONLINE_JUDGE
        freopen("1.in", "r", stdin);
        freopen("1.out", "w", stdout);
    #endif
    solve();
    return 0;
}

/*
5
4 1 2 3 1
(((()(()))(
*/

D - Take a Guess

      预备知识:a + b = a & b + a | b
      已知a1 + a2, a1 + a3, a2 + a3,那么我们就可以用2 * a1 + a2 + a3 - (a2 + a3),求出a1。
      然后求出所有的a1 + ai,( 2 ≤ i ≤ n 2 \leq i \leq n 2in),因为已知了a1,所以我们就可以求出所有的ai。
      求完之后排个序就可以得到答案。
ACcode:
#include<bits/stdc++.h>
using namespace std;

const int N = 1e5 + 100;
typedef long long ll;
typedef pair<int, int> PII;

int a[N], pp[N];

void solve() {
    int n, k, res;
    scanf("%d%d", &n, &k);
    fflush(stdout);
    int sum23 = 0;
    
    printf("and 2 3\n");
    fflush(stdout);
    scanf("%d", &res);
    fflush(stdout);
    sum23 += res;

    printf("or 2 3\n");
    fflush(stdout);
    scanf("%d", &res);
    fflush(stdout);
    sum23 += res;

    for(int i = 2; i <= n; ++ i) {
        printf("and 1 %d\n", i);
        fflush(stdout);
        scanf("%d", &res);
        fflush(stdout);
        pp[i] += res;

        printf("or 1 %d\n", i);
        fflush(stdout);
        scanf("%d", &res);
        fflush(stdout);
        pp[i] += res;
    }

    a[1] = (pp[2] + pp[3] - sum23) / 2;

    for(int i = 2; i <= n; ++ i) a[i] = pp[i] - a[1];
    sort(a + 1, a + 1 + n);
    printf("finish %d\n", a[k]);
    fflush(stdout);
}

int main() {
    solve();
    return 0;
}

/*
a + b
b + c
a + c
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值