题面
我们先假设
a
全部填了
那么假设
a
中有一个
于是可以设计状态
f[i][j]
表示
[i+1,j]
全为
1
时,
f[i][j]←f[i−1][j]
;
若
i=l,j=r
,还有
f[i][j]←min{f[i−1][k]}(i−1≤k≤j)
;也就是选择填这个区间;
若
i=j
,还有
f[i][i]←f[i−1][i−1]+(bi==0?−1:1)
;也就是
i
不填。
这样设计状态的优点就是可以优化成一维,
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=200100;
int n,a[maxn],q;
struct node
{
int l,r;
}c[maxn];
bool cmp(node a,node b)
{
if(a.l==b.l) return a.r>b.r;
return a.l<b.l;
}
struct tree
{
int l,r,mi;
tree *ls,*rs;
tree()
{
ls=rs=NULL;
l=r=mi=0;
}
void update()
{
mi=min(ls->mi,rs->mi);
}
void build(int lx,int rx)
{
l=lx;r=rx;
if(l==r) {mi=(l==0)?0:maxn;return;}
int mid=(l+r)>>1;
(ls=new tree)->build(lx,mid);
(rs=new tree)->build(mid+1,rx);
update();
}
void mdf(int pl,int c)
{
if(l==r) {mi=min(mi,c);return;}
int mid=(l+r)>>1;
if(pl<=mid) ls->mdf(pl,c);
else rs->mdf(pl,c);
update();
}
int qry(int lx,int rx)
{
if(l==lx&&r==rx) return mi;
int mid=(l+r)>>1;
if(rx<=mid) return ls->qry(lx,rx);
else if(lx>mid) return rs->qry(lx,rx);
else return min(ls->qry(lx,mid),rs->qry(mid+1,rx));
}
}*xtr;
int main()
{
scanf("%d",&n);
int num=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
num+=(1-a[i]);
}
(xtr=new tree)->build(0,n);
scanf("%d",&q);
for(int i=1;i<=q;i++)
scanf("%d%d",&c[i].l,&c[i].r);
sort(c+1,c+q+1,cmp);
c[0].l=1;
int p=1;
for(int i=1;i<=n;i++)
{
for(;c[p].l==i;p++)
xtr->mdf(c[p].r,xtr->qry(c[p].l-1,c[p].r));
xtr->mdf(i,xtr->qry(i-1,i-1)+2*a[i]-1);
}
printf("%d",num+xtr->qry(n,n));
return 0;
}