2022牛客国庆集训派对day1

B

题意:

给定一个01字符串,你需要找到最长的一个子串和最长的一个子序列,分别使得其中01的个数相同。

做法:

子序列很好算 2×min(cnt0,cnt1)

子串可以考虑前缀和

将0与1的个数差前缀和 每次询问当前的前缀和x 如果之前出现前缀和为y 使得x+y=0即成立

最后取个最大值就好

void solve() {
    int n; cin >> n;
    string s; cin >> s;
    s = " " + s;
    int ans = 0, cnt = 0;
    map<int,int> mp;
    mp[0] = 0;
    for (int i = 1; i <= n; i++) {
        if (s[i] == '1') cnt++;
        else cnt--;
        if(mp.count(cnt)) ans = max(ans, i - mp[cnt]);
        else mp[cnt] = i;
    }
    cout << ans << " ";
    int cnt1 = 0, cnt0 = 0;
    for (int i = 1; i <= n; i++) {
        if (s[i] == '0') cnt0++;
        else cnt1++;
    }
    cout << min(cnt1, cnt0) * 2 << endl;
}

很神奇的做法:

假设开始线是水平的 然后我们可以找到第一条使得过线和线上方的点大于总点数的线

然后使得这条线倾斜一丢丢就好

map<int, vector<int>>mp;
int n;
void slove() {
    cin >> n;
    mp.clear();
    for (int i = 1; i <= n; i++) {
        int x, y;
        cin >> x >> y;
        mp[y].push_back(x);
    }
    int pre = 0;
    for (auto p : mp) {
        sort(p.second.begin(), p.second.end());
        pre += p.second.size();
        if (pre >= n / 2) {
            pre -= p.second.size();
            for (int x : p.second) {
                pre++;
                if (pre == n / 2) {//找到中间点
                    //x   y 
                    int y = p.first;
                    cout << int(x + 1e8) + 1<<" " << y - 1 << " " << int(x - 1e8) <<" " << y + 1 << endl;
                    break;
                }
            }
            break;
        }
    }    
}

G

题意:

给你n个数,问你有多少个长度不小于2的连续子序列,使得其中最大元素不大于所有元素和的一半。

做法

还是用到容斥原理

int a[N], n, pre[N];
int sum(int L, int R) {
    if (L > R)return 0;
    return pre[R] - pre[L - 1];
}
int LL[N], RR[N];
void slove() {
    cin >> n;
    for (int i = 1; i <= n; i++)cin >> a[i];
    for (int i = 1; i <= n; i++)pre[i] = pre[i - 1] + a[i];
    a[0] = 1e18, a[n + 1] = 1e18;
    stack<int>stk; stk.push(0);
    for (int i = 1; i <= n; i++) {
        while (a[stk.top()] < a[i])stk.pop();
        LL[i] = stk.top();
        stk.push(i);
    }
    while (stk.size())stk.pop();
    stk.push(n + 1);
    for (int i = n; i >= 1; i--) {
        while (a[stk.top()] < a[i])stk.pop();
        RR[i] = stk.top();
        stk.push(i);
    }
    int ans = 0;
    for (int i = 1; i <= n; i++) {
        int L_len = i - LL[i], R_len = RR[i] - i;
        if (L_len <= R_len) {
            int mx = a[i];
            for (int j = LL[i] + 1; j <= i; j++) {
                auto k = lower_bound(pre + i, pre + RR[i], 2 * mx + pre[j - 1]) - pre;
                ans += (k - i);
            }
        }
        else {
            int mx = a[i];
            for (int j = i; j < RR[i]; j++) {
                auto k = lower_bound(pre + LL[i], pre + i, pre[j] - 2 * mx + 1) - pre;
                ans += i - k;
            }
        }
    }
    cout << n * (n + 1) / 2 - ans << endl;
}
posted @ 2022-10-12 15:17  wzx_believer  阅读(21)  评论(0编辑  收藏  举报