Gym - 100712L

是一个单调队列优化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('\n');
    }
    return 0;
}

 

posted @ 2020-03-11 21:33  WeiAR  阅读(103)  评论(0编辑  收藏  举报