ARC 085

来源:互联网 发布:中兴手机刷机软件 编辑:程序博客网 时间:2024/06/06 01:54

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 1e13using 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 1e9using 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;}
原创粉丝点击