CF1178H Stock Exchange

Posted smyjr

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF1178H Stock Exchange相关的知识,希望对你有一定的参考价值。

cf

这题显然可以等价于要找一个 ([1,n])([n+1,2n]) 之间的完美匹配,但是匹配的边随着(t)的变化也会不断变化

所以先要发现一个结论:一组合法的方案如果是在(t)时刻结束,那么一定存在一个交换次数不劣于当前方案的方案,满足这个方案里的交换只发生在时刻 (0) 或时刻 (t) .证明的话,首先我们可以对这个方案里的每一组匹配 (i o j) 分开考虑:

  • 如果在时刻 (0) 或时刻 (t),(i) 的价格 (ge j) 的价格,那么可以使用一次交换解决
  • 否则说明我们需要在中途先依次换成若干个别的元素,显然这一定满足满足第一个元素在时刻 (0) 的价格 (le i)的价格,最后一个元素在时刻 (t) 的价格 (ge j) 价格.进一步的可以发现其实最多只要经过一个元素,因为对于一个中转元素集合,如果所有元素不同时满足在时刻 (0) 的价格 (le i)的价格,在时刻 (t) 的价格 (ge j) 价格这两个条件,那么 (i) 是无法转移到 (j) 的,即只满足前者的元素和只满足后者的元素两两无交

那么先考虑第一问,先二分答案所在时刻,然后贪心的考虑,对于某个之前的元素,如果我们在到达时刻 (t) 的时候的它所对应的中转元素价格越高,那么就越有利于匹配,所以先把所有元素按照在时刻 (0) 时的价格从小到大排序,然后每个 ([1,n]) 里的元素选择价格不超过它的且在时刻 (t) 时的价格最大的元素先换过去;接着把所有元素按照在时刻 (t) 时的价格从大到小排序,再扫一遍,看每个 ([n+1,2n]) 的元素是否可以找到未匹配的价格不小于它的元素匹配

然后是第二问,由于是匹配模型,我们考虑费用流,对每个点建左点右点,然后 (s)([1,n]) 里的左点,([n+1,2n]) 里的左点连 (t) .如果 (i) 可以在时刻 (0) 换成 (j) ,那么左点里面连 (1) 费用的 (i o j) 边,如果 (i) 可以在时刻 (t) 换成 (j) ,那么右点里面连 (1) 费用的 (i o j) 边.注意到空间限制不允许,但是因为 (i o j) 代表 (i) 的价格更高,那么可以按价格从小往大扫,一个点向前面的点连边即可

#include<bits/stdc++.h>
#define LL long long

using namespace std;
const int N=4400+10,NN=N<<2,M=NN*15,inf=1145141;
int rd()
{
    int x=0,w=1;char ch=0;
    while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+(ch^48);ch=getchar();}
    return x*w;
}
int to[M],nt[M],c[M],w[M],hd[NN],tot=1;
void adde(int x,int y,int z,int zz)
{
    ++tot,to[tot]=y,nt[tot]=hd[x],c[tot]=z,w[tot]= zz,hd[x]=tot;
    ++tot,to[tot]=x,nt[tot]=hd[y],c[tot]=0,w[tot]=-zz,hd[y]=tot;
}
int di[NN],a2,pr[NN],fw[NN],ps,pt,tt;
bool vs[NN];
void csfl()
{
    queue<int> q;
    while(1)
    {
        memset(di,0x3f3f3f,sizeof(int)*(tt+1));
        fw[ps]=inf,fw[pt]=0;
        di[ps]=0,vs[ps]=1,q.push(ps);
        while(!q.empty())
        {
            int x=q.front();
            q.pop();
            for(int i=hd[x];i;i=nt[i])
            {
                int y=to[i];
                if(c[i]>0&&di[y]>di[x]+w[i])
                {
                    di[y]=di[x]+w[i];
                    pr[y]=i,fw[y]=min(fw[x],c[i]);
                    if(!vs[y]) vs[y]=1,q.push(y);
                }
            }
            vs[x]=0;
        }
        if(!fw[pt]) return;
        a2+=di[pt]*fw[pt];
        int x=pt;
        while(x!=ps)
        {
            int i=pr[x];
            c[i]-=fw[pt],c[i^1]+=fw[pt];
            x=to[i^1];
        }   
    }
}
int n,nn,s1[N],s2[N],cn[N];
LL a[N],b[N],a1=-1,l,r,ti;
LL nps(int i,LL t){return a[i]*t+b[i];}
bool cmp1(int aa,int bb){return b[aa]!=b[bb]?b[aa]<b[bb]:a[aa]>a[bb];}
bool cmp2(int aa,int bb){return nps(aa,ti)<nps(bb,ti);}

int main()
{
    /////
    n=rd(),nn=n+n;
    for(int i=1;i<=nn;++i) a[i]=rd(),b[i]=rd();
    for(int i=1;i<=nn;++i) s1[i]=s2[i]=i;
    sort(s1+1,s1+nn+1,cmp1);
    l=0,r=1e9+10;
    while(l<=r)
    {
        ti=(l+r)>>1;
        for(int i=1;i<=nn;++i) cn[i]=0;
        for(int i=1,j=0;i<=nn;++i)
        {
            int x=s1[i];
            if(!j||nps(x,ti)>nps(j,ti)) j=x;
            if(x<=n) ++cn[j];
        }
        sort(s2+1,s2+nn+1,cmp2);
        int nw=0;
        for(int i=nn,j=nn;i;--j,i=j)
        {
            while(j>1&&nps(s2[i],ti)==nps(s2[j-1],ti)) --j;
            for(int k=i;k>=j;--k) nw+=cn[s2[k]];
            for(int k=i;k>=j;--k) nw-=s2[k]>n;
            if(nw<0) break;
        }
        if(nw>=0) a1=ti,r=ti-1;
        else l=ti+1;
    }
    if(a1==-1){printf("%lld
",a1);return 0;}
    ps=0,tt=pt=nn+nn+2;
    for(int i=1;i<=nn;++i)
    {
        if(i<=n) adde(ps,i,1,0);
        else adde(i+nn,pt,1,0);
        adde(i,i+nn,inf,0);
    }
    ti=a1,sort(s2+1,s2+nn+1,cmp2);
    for(int i=1,j=1,lp=++tt;i<=nn;++j,i=j)
    {
        while(j<nn&&b[s1[i]]==b[s1[j+1]]) ++j;
        int np=++tt;
        for(int k=i;k<=j;++k) adde(s1[k],np,inf,1);
        for(int k=i;k<=j;++k) adde(np,s1[k],inf,0);
        adde(np,lp,inf,0),lp=np;
    }
    for(int i=1,j=1,lp=++tt;i<=nn;++j,i=j)
    {
        while(j<nn&&nps(s2[i],ti)==nps(s2[j+1],ti)) ++j;
        int np=++tt;
        for(int k=i;k<=j;++k) adde(s2[k]+nn,np,inf,1);
        for(int k=i;k<=j;++k) adde(np,s2[k]+nn,inf,0);
        adde(np,lp,inf,0),lp=np;
    }
    csfl();
    printf("%lld %d
",a1,a2);
    return 0;
}

以上是关于CF1178H Stock Exchange的主要内容,如果未能解决你的问题,请参考以下文章

POJ 3903:Stock Exchange(裸LIS + 二分优化)

1178 H. Stock Exchange

POJ3903 Stock Exchange LIS最长上升子序列

POJ 3903 Stock Exchange 最长上升子序列模板题

如何创建 Hive 派生表?

初入股市之 Hello Stock