CTGU ACM集训队第二次月考核 C题 序列树
涉及算法 贪心
题目描述
在O. michestep王国,有一棵名叫Habaritran的树,树上有一个长度为 n 的序列 a,由于树的营养不足,序列只由 0 和 1 构成,修理工Mitchell mitt觉得序列中每个连续的长度为 k 的子串中的0 与1 数量都相同,这棵树才看起来很nice。当然,修理工Mitchell mitt可以将序列中任何一个 0 修改成 1,也可以将任何一个1修改为0,请问修理工Mitchell mitt最少需要修改多少次,才能将这棵树变得nice。
输入
第一行包含两个正整数,分别为 n和k
第二行包含 n个数,每个数为 0 或者 1
输出
输出一行包含一个正整数,表示最少次数,如果序列怎么修改都不能让这棵树变nice,那么输出"-1"(不包含引号)
样例输入
8 3
10100010
样例输出
-1
数据范围
1 <= k <= n <= 10^6
解题思路
贪心的思想主要集中在 “按b-a升序排序”, 也不难理解, 为了使修改次数最少, 排序后前半部分a比较大, 所以取b, 后半部分b比较大, 所以取a, 以此来使修剪次数最少。
附上一版我的AC代码:
#include<iostream>
#include<algorithm>
using namespace std;
int n, k;
char shu[1000000+10];
int cnt;
struct point{
int cha;
int a;
int b;//a表示改成1,b表示改成0
};
typedef struct point P;
P biao[1000000+10];
bool cmp(point x, point y)
{
return x.cha < y.cha;
}
int main()
{
scanf("%d%d ", &n, &k);
for(int i=1;i<=n;i++)
scanf("%c", &shu[i]);
if(k%2!=0) {
printf("-1");
}else {
for(int i=1;i<=k;i++){
for(int j=i;j<=n;j+=k){
if(shu[j]=='0') (biao[i].a)++;
}
//求a的。
for(int j=i;j<=n;j+=k){
if(shu[j]=='1') (biao[i].b)++;
}
//求b的。
biao[i].cha = biao[i].b - biao[i].a;
}
sort(biao+1, biao+1+k, cmp);
for(int i=1;i<=(k/2);i++){
cnt+=biao[i].b;
}
for(int i=(k/2)+1;i<=k;i++){
cnt+=biao[i].a;
}
printf("%d", cnt);
}
return 0;
}