序列樹 & 貪心 & 考核補題
阿新 • • 發佈:2020-12-22
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
輸出
輸出一行包含一個正整數,表示最少次數,如果序列怎麼修改都不能讓這棵樹變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;
}