题解 修改字符串 DDP基础题

mac2026-08-16  3

题解 修改01串

题目描述

数据范围:

具体做法与心路历程

这道题作为 T 1 T1 T1真心觉得出题人毒瘤好吧是我太菜。看这题目感觉妥妥的贪心,贪心思路都有,且还是对的。可惜只有 50 p t s 50pts 50pts,然后开始优化贪心,搞了个线段树,一码就是 300 + 300+ 300+,结果错了。CYJian线段树贪心A了,还只有200+。考完才知道正解是 D P ! DP! DP!,然而我连想都没想。

具体做法

方法是 D D P DDP DDP。设 f [ i ] [ 0 / 1 ] f[i][0/1] f[i][0/1]表示使第 1 1 1 ~ i i i位全部变成 0 0 0,且有没有对下一位进位的方案数, a [ i ] a[i] a[i]表示原字符串的字符。转移为:

f [ i ] [ 0 ] = m i n ( f [ i − 1 ] [ 0 ] + 1 − a [ i ] , f [ i − 1 ] [ 1 ] + a [ i ] ) f[i][0]=min(f[i-1][0]+1-a[i],f[i-1][1]+a[i]) f[i][0]=min(f[i1][0]+1a[i],f[i1][1]+a[i]). 第 i − 1 i-1 i1位如果没进位,且第 i i i位为 1 1 1,那么答案+1,否则不加,如果第 i − 1 i-1 i1位进位,且第 i i i位不为 1 1 1,那么答案+1,否则不加。在这些情况中取最小值即可。 [ i ] [ 1 ] = m i n ( f [ i − 1 ] [ 0 ] + 2 − a [ i ] , f [ i − 1 ] [ 1 ] + 1 − a [ i ] [i][1]=min(f[i-1][0]+2-a[i],f[i-1][1]+1-a[i] [i][1]=min(f[i1][0]+2a[i],f[i1][1]+1a[i]. 第 i − 1 i-1 i1位没进位,且第 i i i位为 0 0 0,答案+2,为1则+1,第 i − 1 i-1 i1位进位,第 i i i位为 0 0 0则答案+1,否则不加。

这个如果不修改则 O ( n ) O(n) O(n)就做完了,如果修改的话可以考虑 D D P DDP DDP,发现这个式子可以写成广义矩阵的形式,用线段树维护即可。话说我DDP板子题都没打过的蒟蒻这些题倒是做了几道了

C o d e \mathcal{Code} Code

/******************************* Author:galaxy yr LANG:C++ Created Time:2019年11月01日 星期五 22时09分42秒 *******************************/ #include<cstdio> #include<algorithm> #include<string> #include<cstring> using namespace std; struct IO{ template<typename T> IO & operator>>(T&res) { T q=1;char ch; while((ch=getchar())<'0' or ch>'9')if(ch=='-')q=-q; res=(ch^48); while((ch=getchar())>='0' and ch<='9') res=(res<<1)+(res<<3)+(ch^48); res*=q; return *this; } }cin; struct Matrix{ int a[2][2]; int * operator[](const int i) { return a[i]; } const int * operator[](const int i) const { return a[i]; } Matrix operator*(const Matrix p) { Matrix t; t[0][0]=min(a[0][0]+p[0][0],a[0][1]+p[1][0]); t[0][1]=min(a[0][0]+p[0][1],a[0][1]+p[1][1]); t[1][0]=min(a[1][0]+p[0][0],a[1][1]+p[1][0]); t[1][1]=min(a[1][0]+p[0][1],a[1][1]+p[1][1]); return t; } }; const int maxn=3e5+10; const Matrix M0={{{0,1},{2,1}}}; const Matrix M1={{{1,2},{1,0}}}; int n,m,a[maxn]; string s; /*{{{线段树*/ namespace SegmentTree{ Matrix tr[maxn*4]; void update(int k) { tr[k]=tr[k<<1]*tr[k<<1|1]; } void build(int k,int l,int r) { if(l==r) { tr[k]=(a[l]?M1:M0); return; } int mid=(l+r)>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); l update(k); } void modify(int k,int l,int r,int pos) { if(l==r) { tr[k]=(a[pos]?M1:M0); return; } int mid=(l+r)>>1; if(pos<=mid) modify(k<<1,l,mid,pos); else modify(k<<1|1,mid+1,r,pos); update(k); //print(tr[k]); } Matrix query(int k,int l,int r,int x,int y) { if(l>=x && r<=y) return tr[k]; int mid=(l+r)>>1; if(y<=mid) return query(k<<1,l,mid,x,y); if(x>=mid+1) return query(k<<1|1,mid+1,r,x,y); return query(k<<1,l,mid,x,y)*query(k<<1|1,mid+1,r,x,y); } }; /*}}}*/ int main() { //freopen("string.in","r",stdin); //freopen("string.out","w",stdout); cin>>n; s.resize(n+1); s[0]='$'; scanf("%s",&s[1]); cin>>m; for(int i=1;i<=n;i++) a[i]=s[i]-'0'; SegmentTree::build(1,1,n); while(m--) { int opt,l,r; cin>>opt>>l>>r; if(opt==1) { Matrix ans=SegmentTree::query(1,1,n,l,r); printf("%d\n",min(ans[0][0],ans[1][0]+1)); } else { if(a[l]^r) { a[l]=r; SegmentTree::modify(1,1,n,l); } } } }
最新回复(0)