CF2042C 解题报告.19111294

前言

duel 题目,很有价值,但是 luogu 里面我只会写题解而不是解题报告
现在开始吧

广告

luogu 题解传送门,不确定有更好的阅读体验

题意

给出一个 01 串,要求将其分段,计第 \(i\) 段的贡献为第 \(i\) 段中 \(1\) 的个数减去 \(0\) 的个数乘 \((i-1)\),求至少分多少个段,就可以获得至少 \(k\) 的贡献

做法

一开始如果想怎么分段的话很难想,但是稍微思考可以从后往前考虑,考虑一个断点能造成什么贡献,手玩发现如果我们在 \(i\) 这个位置作为断点,我们就可以获得 \(i\) 后面的 \(1\) 的数量减去 \(0\) 的数量,然后对于所有贡献从大到小排序即可。
注意第一个位置不能造成贡献,所以不能计算第一个点的贡献。

代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<climits>
#include<cmath>
#define ll long long

using namespace std;
const int N=2e5+9;
int sum0[N],sum1[N],n,a[N],k,sum[N];

inline void solve(){
    cin>>n>>k;
    for(int i=1;i<=n;i++){
        char s;
        cin>>s;
        a[i]=s-'0';
        sum[i]=sum0[i]=sum1[i]=0;
    }
    sum[n+1]=sum0[n+1]=sum1[n+1]=0;
    for(int i=n;i>=1;i--){
        if(a[i]==0)sum0[i]++;
        else sum1[i]++;
        sum0[i]+=sum0[i+1];
        sum1[i]+=sum1[i+1];
    }
    for(int i=2;i<=n;i++)
        sum[i]=sum1[i]-sum0[i];
    sort(sum+2,sum+n+1);
    reverse(sum+2,sum+n+1);
    int ans=0;
    for(int i=2;i<=n;i++){
        ans+=sum[i];
        if(ans>=k)
            return cout<<i<<endl,void();
    }
    cout<<-1<<endl;
}

int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    int T;
    cin>>T;
    while(T--){
        solve();
    }
    return 0;
}
posted @ 2025-09-25 16:15  zacharyzhongyq  阅读(7)  评论(0)    收藏  举报