zoukankan      html  css  js  c++  java
  • 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]) 的元素是否可以找到未匹配的价格不小于它的元素匹配

    然后是第二问,由于是匹配模型,我们考虑费用流,对每个点建左点右点,然后左点向右点连费用为 (0) 的边,(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;
    }
    
  • 相关阅读:
    React学习笔记
    士兵杀敌(一)
    网络爬虫Java实现抓取网页内容
    德莱联盟
    计算球体积
    在页面上 获取键盘事件
    一起玩转mysql
    腾讯云 做出的 不错的 动画 chrome小插件
    jquery MD5
    json to xml
  • 原文地址:https://www.cnblogs.com/smyjr/p/12335580.html
Copyright © 2011-2022 走看看