连灯-二分
alter-P3718
题意
给定 \(n\) 盏灯的初始状态 \(N/F\),进行最多 \(k\) 次取反,问最短连续状态长度是多少。
思路
写题ing
这题是我自己挑的,所以我知道用什么算法。。。无语。
考虑贪心的话就是每次对最长的连续串的中心取反。思考一下这样子的时间复杂度:优先队列维护最长串,每次取出切一半,放回去两个,不对 \(2/1\) 操作,直到 \(k=0 || pq.empty()\) 似乎是 \(O(nlogn)\) 。试一下。\(1e5\) 不知道 \(pq\) 能不能吃下。
www,贪心不证明,爆零两行泪。为什么??!!
知道了,比如 \(8\) 个 \(N\) ,贪心答案是 \(3\) ,正解是分成 \(5\) 和 \(2\) ,在分 \(5\) 。麻了。
其实真的不是很好想到二分,但好像是有一点感觉的,不是道是不是我知道标签的原因。。
二分最长区间,然后每遍历到一个超过长度的区间就砍,很简单的样子。
还是 \(wa\) 了几个点,这还有什么问题,我贴个 \(check\) 在这
bool chy(int x)
{
int cnt=0,len=0;
for(int i=1;s[i];++i)
{
++len;
if(len>x)
{
len=0;
++cnt;
}
if(s[i]!=s[i+1])
{
len=0;
}
}
return cnt<=k;
}
麻了, \(40\) 分钟切不了一道绿题。为什么 \(wa\) 了???
打暴力试一下,反正就是不看题解。再来 \(15\) 分钟。同样判断方法的对拍也是 \(wa\) 的。
算了。我去进食一下,真的不知道错在哪里,就不浪费时间了。
啊啊啊啊,我贪心的时候想到了的,就是哪个不对 \(2\) 操作,啊啊啊啊。对二操作可能会导致下一个连着的变长。。
正文:很容易想到要用二分,然后长度为一要特判,因为对二操作会让下一个长度变长,一特判了就把二分的左边界改为 \(2\) 。
code
#include <bits/stdc++.h>
#define int long long
using namespace std;
constexpr int maxn = 1e5+10;
constexpr int INF = 0x3f3f3f3f3f3f3f3f;
int n,k;
char s[maxn];
bool chy(int x)
{
int cnt=0,len=0;
for(int i=1;s[i];++i)
{
++len;
if(len>x)
{
++cnt;
len=0;
}
if(s[i]!=s[i+1])
{
len=0;
}
}
return cnt<=k;
}
int binary(int l,int r)
{
int mid,ret;
while(l<=r)
{
mid=l+((r-l)>>1);
if(chy(mid))
{
ret=mid;
r=mid-1;
}
else
{
l=mid+1;
}
}
return ret;
}
char c[3]="FN";
signed main()
{
#ifndef ONLINE_JUDGE
freopen("cjdl.in","r",stdin);
freopen("cjdl.out","w",stdout);
#endif // ONLINE_JUDGE
scanf("%lld%lld",&n,&k);
scanf("%s",s+1);
int cnt=0;
for(int i=1;s[i];++i)
{
if(s[i]==c[i&1])
{
++cnt;
}
}
if(cnt<=k || n-cnt<=k)
{
printf("1\n");
return 0;
}
int ans=binary(2,n/k+2);
printf("%lld\n",ans);
return 0;
}

浙公网安备 33010602011771号