CF1279F New Year and Handle Change 题解
Posted 18Michael
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF1279F New Year and Handle Change 题解相关的知识,希望对你有一定的参考价值。
来翻译一下 cf 评论区一老哥的证明。
首先问题可以转化为选出 \\(k\\) 个长为 \\(l\\) 的区间使得覆盖的 \\(1\\) 个数最多。
不妨设 \\(kl\\le n\\),设选 \\(k\\) 个区间最多能覆盖 \\(f_k\\) 个 \\(1\\),显然存在一种最优方案使得区间两两不交。
下面证明 \\(f_k+1\\ge \\fracf_k+f_k+22\\),即 \\(f\\) 具有凸性。
分别找到 \\(k\\) 时和 \\(k+2\\) 时的一组最优解:
把相交的区间对应连边,如图:
形成了若干连通块,每个连通块内 \\(k\\) 和 \\(k+2\\) 的区间数之差不超过 \\(1\\),因此必然有一个连通块在 \\(k+2\\) 中的区间数比在 \\(k\\) 中的区间数多 \\(1\\),翻转这个连通块:
于是得到了两种 \\(k+1\\) 时的方案,取更优的那组即可,得证。
证明了凸性后就是 wqs 二分的板子题了,时间复杂度 \\(O(n\\log n)\\)。
Code
#include<bits/stdc++.h>
#define LL long long
using namespace std;
int n,l,L,R,mid,t;
LL m,ans;
int a[1000002];
LL f[1000002],g[1000002];
char ch[1000002];
template<class T>void read(T &x)
x=0;int f=0;char ch=getchar();
while(ch<\'0\' || ch>\'9\')f|=(ch==\'-\'),ch=getchar();
while(ch>=\'0\' && ch<=\'9\')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
x=f? -x:x;return ;
inline bool check(int o)
t=0;
for(int i=0;i<l;++i)f[i]=g[i]=0;
for(int i=l;i<=n;++i)
if(f[i-l]<f[t] || (f[i-l]==f[t] && (o? g[i-l]>g[t]:g[i-l]<g[t])))t=i-l;
f[i]=f[t]+a[i-l]+mid,g[i]=g[t]+1;
if(f[i-1]+a[i]<f[i] || (f[i-1]+a[i]==f[i] && (o? g[i-1]>g[i]:g[i-1]<g[i])))f[i]=f[i-1]+a[i],g[i]=g[i-1];
f[i]-=a[i];
if(o || g[n]<=m)ans=min(ans,f[n]+a[n]-min(g[n],m)*mid);
return g[n]<=m;
inline void solve(int c)
for(int i=1;i<=n;++i)a[i]=a[i-1]+(ch[i]!=c);
for(L=0,R=n;L<=R;)
mid=((L+R)>>1);
if(check(0))R=mid-1;
else L=mid+1;
mid=L,check(1);
int main()
read(n),read(m),read(l);
if(1LL*m*l>=n)return 0&puts("0");
scanf("%s",ch+1),ans=n;
for(int i=1;i<=n;++i)ch[i]=(ch[i]<=\'Z\');
solve(0),solve(1);
return 0&printf("%lld",ans);
以上是关于CF1279F New Year and Handle Change 题解的主要内容,如果未能解决你的问题,请参考以下文章