问题描述
有N盏灯排成一列,其中有些灯开着,有些灯关着。小可可希望灯是错落有致的,他定义一列灯的状态的不优美度为这些灯中最长的连续的开着或关着的灯的个数。小可可最多可以按开关k次,每次操作可以使该盏灯的状态取反:原来开着的就关着,反之开着。现在给出这些灯的状态,求操作后最小的不优美度。
—————————————————————————————————————————————
输入格式
第一行两个整数n,k
第二行是一个长度为n的字符串,其中有两种字符:N和F。其中N表示该灯开着,F表示该灯关着
输出格式
最小的不优美度
样例 #1
样例输入 #1
8 1
NNNFFNNN
样例输出 #1
3
—————————————————————————————————————————————
提示
30%的数据:1 ≤ K ≤ N ≤ 20;
50%的数据:1 ≤ K ≤ N ≤ 300;
另有15%的数据:1 ≤ N ≤ 100000,字符串为全N或全F;
100%的数据:1 ≤ K ≤ N ≤ 100000。
—————–———————————————————————————————————————
解题思路
首先,求最小的最大值,且满足单调性,所以可以使用二分。
需要注意的是:
1.二分可以求出最小的不优美度,但是最小值为1,需要进行特判
2.二分得出的是一个可能的不优美度,[left, right]是最小不优美度可能的范围,其中初始left=1,right=n/k+1(尝试理解一下,不理解的话right=n也可)
在本题中,最小不优美度为1,需要进行特判:
比如FNNNFFNN,若最多可以按4次开关,求最小不优美度。
当不优美度为1时,有且仅有两种情况:
FNFNFNFN(需要按3次开关) 或
NFNFNFNF(需要按5次开关)
容易得出,想要一排灯不优美度为1仅有两种情况,且变成这两种情况所需按开关次数之和刚好为灯的数量
那么只要特别判断这两种情况即可
—————————————————————————————————————————————
解题代码
#include<iostream>
using namespace std;
int n, k;
string s;
int main()
{
cin >> n >> k >> s;
char c[2] = {'F', 'N'};//标记
int p = 0;
for(int i = 0; i < n; i++)//进行特判
if(s[i] == c[i%2])
p++;
if(p <= k || n-p <= k){
cout << 1 << endl;
return 0;
}
int l = 2, r = n/k+1, mid;
int cnt = 0;
while(l <= r){
mid = (l+r)/2;//一个可能的不优美度
cnt = 0;
for(int i = 0, j = 0, ans = 0; i < n; i++){
if(s[i] == s[j])
ans++;
else
j = i, ans = 1;
if(mid < ans)
j = i+1, ans = 0, cnt++;
}
//i表示连续的灯的最右端,j表示连续的灯的最左端,ans表示连续的灯的长度,cnt表示最少需要按多少次灯
if(cnt <= k){
r = mid - 1;
}
else{
l = mid + 1;
}
}
cout << l << endl;
return 0;
}