专栏文章
题解 CF2042C
CF2042C题解参与者 5已保存评论 4
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 4 条
- 当前快照
- 1 份
- 快照标识符
- @miqvi4kt
- 此快照首次捕获于
- 2025/12/04 11:25 3 个月前
- 此快照最后确认于
- 2025/12/04 11:25 3 个月前
题意:
给一个 0-1 串分段,每段内元素的分数从左到右递增,问使得位置为 的总分数至少比位置为 的总分数多 的最小段数。
思路:
算是一道有些反直觉的题目,一眼让人容易想到直接给序列本身分段,陷入错误循环。实际上得到正解只需要注意到一个结论:在某个位置 后断点,对总分数的贡献是一定的。而这个贡献等于 后的 个数减去 个数。
证明也不难,在 后断点,所有 之后的元素分数全部增加 ,对于前面答案的统计没有任何影响,断点之间也不会有任何影响。
只需从后往前枚举断点并且算出所有 个断点对答案的贡献,然后从大到小排序,贪心的取断点即可。
举个例子,考虑样例中 的字符串,设 后断点的贡献为 ,则有 。我们贪心的取断点,最多可以使得 个数和 个数之差达到 。满足 的条件只需取两个 ,将序列分成三段。
程序如下:
CPP#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=2e5+5;
int T,n,k,a[N];
char str[N];
int main(){
scanf("%d",&T);
while(T--){
scanf("%d%d%s",&n,&k,str+1);
int cnt0=0,cnt1=0;
for(int i=n;i>=1;i--){
if(str[i]=='0')cnt0++;
else cnt1++;
a[i]=cnt1-cnt0;//对于每个位置求它的贡献
}
sort(a+2,a+n+1);//排序,注意不能包含首项
long long sum=0,ans=1;
bool flag=true;
for(int i=n;i>1;i--){
if(a[i]<=0){
flag=false;
break;
}
sum+=a[i],ans++;
if(sum>=k)break;
}
if(!flag||sum<k)printf("-1\n");
else printf("%d\n",ans);
}
}
THE END
相关推荐
评论
共 4 条评论,欢迎与作者交流。
正在加载评论...