牛客周赛 Round 90——真爱粉Tk(三)

题目

真爱粉Tk(三)

题解

根据题意,像这种最大值最小,最小值最大的问题,就引导我们要用二分。对于一个元素而言,我们要怎么知道他有多少个25对呢?我们可以存储2的个数,每次遇到5就可以和前面c2个2结合形成25对,所以我们可以存储下来当前元素有多少个2,多少个5,还有多少个25对,每次拼接就增加了 前面元素2的个数 * 当前元素5的个数 + 当前元素的25对数。我们可以预处理init()出每个元素这些的个数。然后进行二分查找check(),每次放不下了再新建一段,最后看看段数是否小于等于k段。

参考代码

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
#define int long long
int n, k;
vector<int> cnt2(N), cnt5(N), cnt25(N);
vector<string> a(N);

void init(int u) {
    int c2 = 0, c5 = 0, c25 = 0;
    for(auto c : a[u]) {
        if(c == '2') {
            c2++;
        }else if(c == '5') {
            c5++;
            c25 += c2;
        }
    }
    cnt2[u] = c2, cnt5[u] = c5, cnt25[u] = c25;
}

bool check(int mid) {
    int sg = 1;
    int tc2 = 0, c25 = 0;
    for(int i = 0; i < n; i++) {
        int nc25 = c25 + cnt25[i] + cnt5[i] * tc2;
        int nc2 = tc2 + cnt2[i];
        if(nc25 > mid) {
            sg++;
            tc2 = cnt2[i];
            c25 = cnt25[i];
        }else {
            c25 = nc25;
            tc2 = nc2;
        }
    }
    return sg <= k;
}

signed main() {
    cin >> n >> k;
    a.resize(n);
    cnt2.resize(n), cnt5.resize(n), cnt25.resize(n);
    
    for(int i = 0; i < n; i++) {
        cin >> a[i];
        init(i);
    }
        
    int l = 0, r = 1e18;
    while(l < r) {
        int mid = l + r >> 1;
        if(check(mid)) r = mid;
        else l = mid + 1;
    }
    cout << l << endl;
    return 0;
}
posted @ 2025-04-21 10:37  PZnwbh  阅读(46)  评论(0)    收藏  举报