显然DP题...
f[i][0]表示这个点不装路由器,f[i][1]表示装路由器
转移也很简单,在前面一段区间找最小值就好了
但是直接转移是$O(n*k)$的,会T掉
大佬说这个东西有单调性,但是菜鸡我找不到,因为是区间问题,所以线段树强上
区间查询+单点修改
1 #include<bits/stdc++.h>
2 #define int long long
3 #define inf (0x7f7f7f7f7f7f7f)
4 using namespace std;
5 inline int read(){
6 int ans=0,f=1;char chr=getchar();
7 while(!isdigit(chr)){if(chr=='-') f=-1;chr=getchar();}
8 while(isdigit(chr)){ans=(ans<<3)+(ans<<1)+chr-48;chr=getchar();}
9 return ans*f;
10 }const int M = 2e5+5;
11 struct Segment_Tree{
12 int s[M<<2];
13 #define mid (l+r>>1)
14 #define ls (i<<1)
15 #define rs (i<<1|1)
16 inline void Push_Up(int i){s[i]=min(s[ls],s[rs]);}
17 void Build(int i,int l,int r){
18 if(l==r)return (void)(s[i]=inf);
19 Build(ls,l,mid),Build(rs,mid+1,r);
20 Push_Up(i);
21 }void Update(int i,int l,int r,int pos,int x){
22 if(l==r)return (void)(s[i]=min(s[i],x));
23 if(pos<=mid) Update(ls,l,mid,pos,x);
24 else Update(rs,mid+1,r,pos,x);
25 Push_Up(i);
26 }int Query(int i,int l,int r,int ql,int qr){
27 if(ql<=l&&r<=qr)return s[i];
28 int t1=inf,t2=inf;
29 if(ql<=mid) t1=Query(ls,l,mid,ql,qr);
30 if(qr>mid) t2=Query(rs,mid+1,r,ql,qr);
31 return min(t1,t2);
32 }
33 }T1,T2;
34 char s[M];
35 int n,m,k,f[M][2];
36 signed main(){
37 n=read(),k=read();
38 scanf("%s",s+2);
39 T1.Build(1,1,n),T2.Build(1,1,n);
40 memset(f,0x3f,sizeof(f));
41 T2.Update(1,1,n,1,f[1][0]=f[1][1]=0);
42 for(int i=2;i<=n+1;i++){
43 f[i][0]=T1.Query(1,1,n,max(i-k,1ll),i-1);
44 if(s[i]=='1') f[i][1]=T2.Query(1,1,n,max(1ll,i-k-1),i-1)+i-1;
45 else f[i][1]=min(T1.Query(1,1,n,max(1ll,i-k-1),i-1),min(f[i-1][0],f[i-1][1]))+i-1;
46 T2.Update(1,1,n,i,min(f[i][0],f[i][1]));
47 if(s[i]=='1') T1.Update(1,1,n,i,f[i][1]);
48 }cout<<min(f[n+1][0],f[n+1][1]);
49 return 0;
50 }
知识兔