E
最小割模板题不会做系列。
其实问题就是每个数选择保留或者不保留各有一个花费,然后有nlogn个关系形如:如果i不保留,j也一定不能保留
正数的和为总价值,减去最小割就是答案
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
#define inf 1e13
using namespace std;
const int maxn = 210;
const int maxm = 110000;
int n,st,ed;
int s[maxn];
struct edge{int y,nex;ll c;}a[maxm]; int len,fir[maxn];
inline void ins(const int x,const int y,const ll c)
{
a[++len]=(edge){y,fir[x],c};fir[x]=len;
a[++len]=(edge){x,fir[y],0};fir[y]=len;
}
queue<int>q;
int h[maxn];
bool bfs()
{
for(int i=1;i<=ed;i++) h[i]=0;
h[st]=1; q.push(st);
while(!q.empty())
{
const int x=q.front(); q.pop();
for(int k=fir[x],y=a[k].y;k;k=a[k].nex,y=a[k].y) if(a[k].c&&!h[y])
h[y]=h[x]+1,q.push(y);
}
return h[ed]>0;
}
ll dfs(const int x,const ll flow)
{
if(x==ed) return flow;
ll delta=0;
for(int k=fir[x],y=a[k].y;k;k=a[k].nex,y=a[k].y) if(a[k].c&&h[y]==h[x]+1)
{
ll mink=dfs(y,min(a[k].c,flow-delta));
a[k].c-=mink; a[k^1].c+=mink;
delta+=mink;
if(delta==flow) return delta;
}
if(!delta) h[x]=0;
return delta;
}
ll flow()
{
ll re=0;
while(bfs())
re+=dfs(st,LLONG_MAX);
return re;
}
ll re;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&s[i]);
if(s[i]>0) re+=(ll)s[i];
}
len=1; //
st=n+1,ed=st+1;
for(int i=1;i<=n;i++)
{
if(s[i]>0) ins(i,ed,(ll)s[i]);
if(s[i]<0) ins(st,i,(ll)-s[i]);
for(int j=i+i;j<=n;j+=i) ins(i,j,inf);
}
printf("%lld\n",re-flow());
return 0;
}
F
不同的位最少可以转化成相同的位最多(不转直接做也行)
然后位置i,如果bi=1,覆盖他可以得到1的价值,bi=0,覆盖他可以得到-1的价值,问题变成若干个区间,每个区间选或不选,要求选出的区间并集的价值和最大。
将区间放到左端点处理,从1~n枚举左端点,假设当前枚举的左端点是i,设f[r]表示处理了1~i-1的左端点,区间最远覆盖到r的最大价值,线段树优化转移
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
#define inf 1e9
using namespace std;
inline void up(int &x,const int &y){if(x<y)x=y;}
const int maxn = 210000;
int n,m;
int b[maxn],s[maxn],f[maxn];
vector<int>V[maxn];
int segf[maxn<<2],segd[maxn<<2];
void pushup(int seg[],const int x){ seg[x]=seg[x<<1]>seg[x<<1|1]?seg[x<<1]:seg[x<<1|1]; }
void build(const int x,const int l,const int r)
{
if(l==r) { segd[x]=l>=0?-inf:0; return; }
int mid=l+r>>1,lc=x<<1,rc=lc|1;
build(lc,l,mid); build(rc,mid+1,r);
pushup(segd,x);
}
int lx,rx,loc,c;
void upd(int seg[],const int x,const int l,const int r)
{
if(l==r) { seg[x]=c; return; }
int mid=l+r>>1,lc=x<<1,rc=lc|1;
if(loc<=mid) upd(seg,lc,l,mid);
else upd(seg,rc,mid+1,r);
pushup(seg,x);
}
int query(int seg[],const int x,const int l,const int r)
{
if(rx<l||r<lx) return -inf;
if(lx<=l&&r<=rx) return seg[x];
int mid=l+r>>1,lc=x<<1,rc=lc|1;
return max(query(seg,lc,l,mid),query(seg,rc,mid+1,r));
}
int re;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&b[i]),re+=!b[i];
for(int i=1;i<=n;i++) s[i]=s[i-1]+(b[i]?1:-1);
build(1,0,n);
for(int i=1;i<=n;i++) f[i]=-inf;
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
int l,r; scanf("%d%d",&l,&r);
V[l].push_back(r);
}
for(int i=1;i<=n;i++)
{
for(int j=0;j<V[i].size();j++)
{
int r=V[i][j];
lx=0,rx=i-1; int cc=query(segf,1,0,n);
up(f[r],cc+s[r]-s[i-1]);
lx=i-1,rx=r-1; cc=query(segd,1,0,n);
up(f[r],cc+s[r]);
loc=r,c=f[r];
upd(segf,1,0,n);
c=f[r]-s[r]; upd(segd,1,0,n);
}
}
int ans=0;for(int i=1;i<=n;i++) up(ans,f[i]);
printf("%d\n",n-(re+ans));
return 0;
}