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;
}

浙公网安备 33010602011771号