2015 ACM Amman Collegiate Programming Contest L.Alternating StringsII

来源:互联网 发布:c语言线程同算法 编辑:程序博客网 时间:2024/06/08 07:09


题目大意:

给你长度为N的一个01字符串,要求我们将其割分成若干个连续子序列,使得每个子序列的长度都不超过K,而且保证每个子序列,要么是单独的一个数,要么是非01间差排列的子序列(01间差排列:1010,010101,.....................)。


思路:


我们通过做这套题的D题的时候不难发现,对于可以割开的字符串,其具有单调性,显然字符串越长,越可能作为割分的子序列(就是非01间差排列的字符串).


我们设定Dp【i】,表示以i作为结尾的时候,需要割分的最小次数,那么显然有:

①Dp【i】=min(Dp【j】+1,Dp【i】);需要保证从j+1到位子i的排列是可行方案。

②Dp【i】=min(Dp【i-1】+1,Dp【i】);


考虑到①中,可行方案的位子具有单调性,所以我们二分一个点,使得这个点是从右往左扫,第一个构成可行方案的位子。

那么我们有:Dp【i】=min(Dp【i】,Dp【j】)【max(i-k,0)<=j<=pos】;

然后我们套个线段树加速转移即可。


时间复杂度O(nlogn)


Ac代码:

#include<stdio.h>#include<string.h>#include<iostream>using namespace std;const int INF=0x3f3f3f3f;int sum[105550*5],lazy[105550*5];void pushup(int rt){    sum[rt]=min(sum[rt<<1],sum[rt<<1|1]);}void pushdown(int rt){    if(lazy[rt]){        lazy[rt<<1]+=lazy[rt];        lazy[rt<<1|1]+=lazy[rt];        sum[rt<<1]+=lazy[rt];        sum[rt<<1|1]+=lazy[rt];        lazy[rt]=0;    }}void build(int rt,int l,int r){    lazy[rt]=sum[rt]=0;    if(l==r) {sum[rt]=0;return ;}    int m = r+l >> 1;    build(rt<<1  ,l  ,m);    build(rt<<1|1,m+1,r);    pushup(rt);}void update(int rt,int l,int r,int L,int R,int v){    if(L<=l&&r<=R){        lazy[rt]+=v;        sum[rt]+=v;        return ;    }    pushdown(rt);    int m = r+l >> 1;    if(L<=m) update(rt<<1  ,l  ,m,L,R,v);    if(R> m) update(rt<<1|1,m+1,r,L,R,v);    pushup(rt);}int query(int rt,int l,int r,int L,int R){    if(L<=l&&r<=R) return sum[rt];    pushdown(rt);    int m = r+l >> 1,ans = INF;    if(L<=m) ans = min(ans,query(rt<<1  ,l  ,m,L,R));    if(R> m) ans = min(ans,query(rt<<1|1,m+1,r,L,R));    pushup(rt);    return ans;}int temp[150000];int dp[150000];char a[150000];int main(){    int t;    scanf("%d",&t);    while(t--)    {        int n,k;        scanf("%d%d",&n,&k);        scanf("%s",a+1);        dp[0]=0;        memset(temp,0,sizeof(temp));        for(int i=1;i<=n;i++)dp[i]=0x3f3f3f3f;        for(int i=n;i>=1;i--)        {            int cnt=0;            if(a[i]==a[i+1])cnt=1;            if(i==n)temp[i]=0;            else temp[i]=temp[i+1]+cnt;        }        temp[0]=temp[1];        build(1,0,n);        for(int i=1;i<=n;i++)        {            dp[i]=min(dp[i],dp[i-1]+1);            int l=max(i-k+1-1,0);            int r=i-1;            int pos=-1;            while(r-l>=0)            {                int mid=(l+r)/2;                if(temp[mid+1]-temp[i]>0)                {                    pos=mid;                    l=mid+1;                }                else r=mid-1;            }            if(pos!=-1)dp[i]=min(dp[i],query(1,0,n,max(i-k,0),pos)+1);            update(1,0,n,i,i,dp[i]);        }        printf("%d\n",dp[n]-1);    }}










阅读全文
0 0