Atcoder ARC085 F NRE
海明距离好像不知道是什么东西,这道题目还是直接看DOFY dalao的题解的。
似乎这道题目只能有一种设计状态的方法,其他方法都会GG。
设f[i][j]表示[a(i+1),aj]中全部填1,[1,i]的海明距离最小值。
好吧状态有点绕,不过我们考虑区间覆盖,覆盖某个区间的时候可能会覆盖到后面的一段连续的数,所以可以如此设计状态(骚)
f[i][j]可以由f[i-1][j]转移过来,也可以由min(f[i-1][k]) (l-1<=k<=r) 转移而来,就是选择这个区间。也可以由f[i-1][i-1]+(bi==0?-1:1)转移而来,就是不填这一位。
所以第一个转移直接转移,第二个转移相当于求一个区间的最小值单点修改,第三个转移相当于单点修改。用线段树维护一下就OK了
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define maxn 200010
using namespace std;
struct edge{
int l,r;
}c[maxn];
bool cmp(edge a,edge 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=0;
mi=0x3f3f3f3f;
}
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:0x3f3f3f3f);
return;
}
int mid=(l+r)>>1;
(ls=new tree)->build(lx,mid);
(rs=new tree)->build(mid+1,rx);
update();
}
void modify(int pos,int num)
{
if(l==r) {
mi=min(mi,num);
return;
}
int mid=(l+r)>>1;
if(pos<=mid) ls->modify(pos,num);
else rs->modify(pos,num);
update();
}
int query(int lx,int rx)
{
if(l==lx&&r==rx) return mi;
int mid=(l+r)>>1;
if(lx>mid) return rs->query(lx,rx);
else if(rx<=mid) return ls->query(lx,rx);
else return min(ls->query(lx,mid),rs->query(mid+1,rx));
}
}*xtr;
int n,q,b[maxn];
int main()
{
scanf("%d",&n);
int ans=0;
for(int i=1;i<=n;++i) scanf("%d",&b[i]),ans+=(1-b[i]);
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);
(xtr=new tree)->build(0,n);
int p=1;
for(int i=1;i<=n;++i)
{
for(;c[p].l==i;++p)
xtr->modify(c[p].r,xtr->query(i-1,c[p].r));
xtr->modify(i,xtr->query(i-1,i-1)+(b[i]==0?-1:1));
}
cout<<ans+xtr->query(n,n);
return 0;
}