P3718 [AHOI2017初中组]alter
贪心+二分答案
二分最终答案长度
主要问题在check上
~~我代码写得巨丑,大家还是不要看我的代码了~~
------------
1:当mid大于1的时候,贪心策略是这样的:
当前连续的长度大于mid时,我不反转最后一个,我也不管它具体反转哪一个,我直接跳过这mid+1个,也就是开始处理i+1。举个例子,
mid=3,k=1,NNNNNNN,我反转第4个,变成NNNFNNN
mid=3,k=1,NNNNFFF,我反转前3个的任意一个
不管怎么反转,前4个对后面是没有影响了,那我就不用管具体怎么反转的
2:当mid等于1的时候,贪心策略是这样的:
跑两遍check,反转第一个,或者不反转第一个,两种情况有一个能行就ok
------------
#include <iostream> #include <cstdio> #include <queue> #include <algorithm> #include <cmath> #include <cstring> #define inf 2147483647 #define N 1000010 #define p(a) putchar(a) #define For(i,a,b) for(int i=a;i<=b;++i) //by war //2019.8.13 using namespace std; int n,k,l,r,mid,a[N],cnt,now; char c[N]; void in(int &x){ int y=1;char c=getchar();x=0; while(c<'0'||c>'9'){if(c=='-')y=-1;c=getchar();} while(c<='9'&&c>='0'){ x=(x<<1)+(x<<3)+c-'0';c=getchar();} x*=y; } void o(int x){ if(x<0){p('-');x=-x;} if(x>9)o(x/10); p(x%10+'0'); } bool check1(int x,int t){ int lf=k-1; For(i,1,n) if(c[i]=='N') a[i]=1; else a[i]=0; cnt=1;now=t; For(i,2,n){ if(a[i]==now){ ++cnt; if(cnt>x){ a[i]^=1; if(x!=1){ now=a[i+1]; cnt=0; } else{ now=a[i]; cnt=1; } if(--lf<0) return 0; } } else{ now=a[i]; cnt=1; } } return 1; } bool check(int x){ int lf=k; For(i,1,n) if(c[i]=='N') a[i]=1; else a[i]=0; cnt=1;now=a[1]; For(i,2,n){ if(a[i]==now){ ++cnt; if(cnt>x){ a[i]^=1; if(x!=1){ now=a[i+1]; cnt=0; } else{ now=a[i]; cnt=1; } if(--lf<0){ if(x==1){ if(check1(x,a[1]^1)) return 1; return 0; } return 0; } } } else{ now=a[i]; cnt=1; } } return 1; } signed main(){ in(n);in(k); cin>>(c+1); l=1;r=n; while(l<r){ mid=(l+r)>>1; if(check(mid)) r=mid; else l=mid+1; } o(l); return 0; }