トピックリンク:こちらをクリックして壁紙
解決:
貪欲ように見える、そうではありません。。。
我々は定義([i]が\ F)\を表すのみ覆う\を(1 \ SIM I \)最低限必要なコストは、その後、\は(私は\) 0点、容易に入手可能である(\ F [I] =分(F [I]、F [I-1] + I)\)
とき考えてみましょう\(私は\)する場合があることを行う方法です\(私は\) 1、定義によって、私たちは移転しないとき(私は\)\を位置の値を、転送\(I + K \)この位置に値
もちろん、限り\(1つの\ SIM P(IKは \ルpは\ルI + K-1を)\) カバーされている、その後、再選択\(I \)、\ (1 \ SIM I + Kは\)することができそれは覆われています。
我々は、セグメントツリーとの間隔を維持\(F \)最小値を、各転送は、転送の最小値を見つけることができます。最後に、境界条件を決定するノート。
コード:
#include<bits/stdc++.h>
#define ls q<<1
#define rs q<<1|1
#define int long long
using namespace std;
const int N=2e5+1;
const int maxn=1e15;
char s[N];
int n,k,f[N],mn[N<<2];
int min(int a,int b){return b<a?b:a;}
int max(int a,int b){return b<a?a:b;}
void update(int q){mn[q]=min(mn[ls],mn[rs]);}
void ins(int q,int l,int r,int x,int v){
if(l==r) return mn[q]=v,void();
int mid=l+r>>1;
if(mid>=x) ins(ls,l,mid,x,v);
else ins(rs,mid+1,r,x,v);
update(q);
}
int query(int q,int l,int r,int L,int R){
if(R<L) return 1e18;
if(l>=L&&r<=R) return mn[q];
int mid=l+r>>1,re=maxn;
if(mid>=L) re=min(re,query(ls,l,mid,L,R));
if(mid<R) re=min(re,query(rs,mid+1,r,L,R));
return re;
}
int read(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;
}
signed main(){
n=read(),k=read();
scanf("%s",s+1);
memset(mn,127,sizeof(mn));
memset(f,127,sizeof(f));f[0]=0;
for(register int i=1;i<=n;i++){
if(s[i]=='1'){
int p=min(n,i+k);
int v=query(1,1,n,max(1,i-k-1),p-1);
if(i-k-1<=0) f[p]=min(f[p],i);
f[p]=min(f[p],v+i);ins(1,1,n,p,f[p]);
}else f[i]=min(f[i],f[i-1]+i),ins(1,1,n,i,f[i]);
}
printf("%lld\n",f[n]);
return 0;
}