是一个单调队列优化dp的典型例子。f[i]=min(f[j])+1,从[i-k,i-1]中转移过来,维护单调递增的队列,每次取队首元素+1就好了。
转移分两种情况,[0,i]或者[i-k,i]这个区间里全是01交替的,那么你只能选f[i-1]也就是最大的,取队尾元素就可以了;否则取队首。
#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) using namespace std; int T,n,k,top,tail,cnt; int f[N];//前i个满足条件,最少要切多少次 int q[N]; char c[N]; bool flag; 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'); } signed main(){ in(T); while(T--){ in(n);in(k); cin>>(c+1); memset(f,0,sizeof(f)); memset(q,0,sizeof(q)); top=tail=cnt=0; f[0]=-1;top=0; cnt=tail=q[1]=1; For(i,2,n){ while(top<=tail&&q[tail]-q[top]>=k) top++; if(c[i]==c[i-1]){ cnt=1; f[i]=f[q[top]]+1; } else{ cnt++; if(cnt>=i-q[top]||cnt==i) f[i]=f[q[tail]]+1; else f[i]=f[q[top]]+1; } while(top<=tail&&f[q[tail]]>f[i]) tail--; q[++tail]=i; } o(f[n]);p(' '); } return 0; }