您的位置:首页 > 其它

2015 ACM Amman Collegiate Programming Contest L.Alternating StringsII

2017-08-11 16:00 555 查看


题目大意:

给你长度为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
-1);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐