zoukankan      html  css  js  c++  java
  • UOJ32【UR #2】跳蚤公路

    一个有向图,边权为(w_i+s_ix)的形式,其中(s_iin[-1,1])(w_i)可以为负数。

    (1)出发,对于每个点(v),问整数(x)的个数,使得:从(1)(v)的过程中不会得到无限小的权值和(也就是说不存在某个负环,可以从(1)到达,可以到达(v)

    (nle 100,mle 10000)


    没想到Bellman-Ford居然有SPFA不能做的实际用途!

    现在的主要问题是找到(x)什么取值的时候没有负环。

    之前想了些做法但是它们都假掉了。另外提醒个看起来显然但是假了的结论:合法的(x)不一定连续。

    正解考虑Bellman-Ford中判负环的方法。设(f_{i,v})表示经过至多(i)步后到达(v)点的最短距离。于是(f_{n,v}<f_{n-1,v})(v)在负环内的充分不必要条件(因为如果不存在负环,最短路不会走环,所以第(n)步不会进行更新)。如果出现了这样的(v),那么它能到达的点都可以被贡献到。

    于是考虑(f_{n,v}ge f_{n-1,v})的条件。设(g_{i,v,k})表示从经过至多(i)步后到达(v)点的,且(x)的系数为(k)的最短距离。

    那么条件为:(min_a g_{n,v,a}+axge min_b g_{n-1,v,b}+bx)。解不等式即可,求出(v)的贡献。

    怎么解?显然等价于(forall a,exist b, g_{n,v,a}+axge g_{n-1,v,b}+bx)。解了之后求个并再求个交。

    维护解集的时候需要维护若干个区间,有些麻烦(尤其是没有意识到这一点的我调了好久)。

    总时间复杂度(O(n^4))


    using namespace std;
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <vector>
    #include <list>
    #define N 105
    #define ll long long
    #define INF 2000000000000000000
    int n,m;
    struct EDGE{
    	int to,w,s;
    	EDGE *las;
    } e[N*N];
    int ne;
    EDGE *last[N];
    void link(int u,int v,int w,int s){
    	e[ne]={v,w,s,last[u]};
    	last[u]=e+ne++;
    }
    ll g[N][N][N+N];
    void upd(ll &x,ll y){
    	x=min(x,y);
    }
    struct itv{ll l,r;};
    itv operator&(itv a,itv b){return {max(a.l,b.l),min(a.r,b.r)};}
    itv operator|(itv a,itv b){return {min(a.l,b.l),max(a.r,b.r)};}
    list<itv> s[N];
    void merge(list<itv> &a,list<itv> b){
    	auto p=a.begin(),q=b.begin();
    	while (p!=a.end() && q!=b.end()){
    		if (p->l<q->l){
    			p->l=q->l;
    			if (p->l>p->r)
    				p=a.erase(p);
    		}
    		else if (p->l>q->l){
    			q->l=p->l;
    			if (q->l>q->r)
    				q=b.erase(q);
    		}
    		else{
    			if (q->r>p->r){
    				q->l=p->r+1;
    				++p;
    			}
    			else if (p->r>q->r){
    				a.insert(p,(itv){p->l,q->r});
    				p->l=q->r+1;
    				++q;
    			}
    			else
    				++p,++q;
    		}
    	}
    	for (;p!=a.end();p=a.erase(p));
    }
    int c[N][N];
    int main(){
    	freopen("in.txt","r",stdin);
    //	freopen("out.txt","w",stdout);
    	scanf("%d%d",&n,&m);
    	for (int i=1;i<=m;++i){
    		int u,v,w,s;
    		scanf("%d%d%d%d",&u,&v,&w,&s);
    		link(u,v,w,s);
    	}
    	memset(g[0],127,sizeof g[0]);
    	g[0][1][0 +N]=0;
    	for (int i=0;i<n;++i){	
    		memcpy(g[i+1],g[i],sizeof g[i]);
    		for (int j=1;j<=n;++j)	
    			for (int k=-i;k<=i;++k)
    				if (g[i][j][k+N]<INF)
    					for (EDGE *ei=last[j];ei;ei=ei->las){
    //						printf("(%d,%d,%d)<-(%d,%d,%d)
    ",i+1,ei->to,k+ei->s,i,j,k);
    						upd(g[i+1][ei->to][k+ei->s+N],g[i][j][k+N]+ei->w);
    					}
    	}
    	for (int v=1;v<=n;++v){
    		s[v].push_back((itv){-INF,INF});
    		for (int a=-n;a<=n;++a){
    			if (g[n][v][a+N]>=INF)
    				continue;
    			ll L=-INF-1,R=INF+1;
    			for (int b=-n;b<=n;++b){
    				if (g[n-1][v][b+N]>=INF)
    					continue;
    				int c=b-a;
    				if (c==0){
    					if (g[n][v][a+N]-g[n-1][v][b+N]>=0){
    						L=INF,R=-INF;
    						break;
    					}
    				}
    				else if (c>0)
    					L=max(L,(ll)floor((double)(g[n][v][a+N]-g[n-1][v][b+N])/c));
    				else
    					R=min(R,(ll)ceil((double)(g[n][v][a+N]-g[n-1][v][b+N])/c));
    			}
    			if (L>=R-1)
    				continue;
    			list<itv> t;
    			t.clear();
    			if (-INF<=L)
    				t.push_back((itv){-INF,L});
    			if (R<=INF)
    				t.push_back((itv){R,INF});
    			merge(s[v],t);
    		}
    	}
    	for (int i=1;i<=n;++i)
    		c[i][i]=1;
    	for (int i=1;i<=n;++i)
    		for (EDGE *ei=last[i];ei;ei=ei->las)
    			c[i][ei->to]=1;
    	for (int k=1;k<=n;++k)
    		for (int i=1;i<=n;++i)
    			for (int j=1;j<=n;++j)
    				c[i][j]|=c[i][k]&c[k][j];
    	for (int v=1;v<=n;++v){
    		list<itv> ans({(itv){-INF,INF}});
    		for (int u=1;u<=n;++u)
    			if (c[1][u] && c[u][v])
    				merge(ans,s[u]);
    		ll tmp=0;
    		for (auto p=ans.begin();p!=ans.end();++p)
    			tmp+=p->r-p->l+1;
    		printf("%lld
    ",tmp>INF/2?-1:tmp);
    	}
    	return 0;
    }
    
  • 相关阅读:
    《应用Yii1.1和PHP5进行敏捷Web开发》学习笔记(转)
    YII 小模块功能
    Netbeans代码配色主题大搜集
    opensuse 启动巨慢 解决方法 90s多
    opensuse 安装 网易云音乐 rpm netease music
    linux qq rpm deb opensuse
    openSUSE 安装 alien
    第一行代码 Android 第2版
    Android Studio AVD 虚拟机 联网 失败
    docker error during connect: Get http://%2F%2F.%2Fpipe%2Fdocker_engine/v1.29/containers/json: open //./pipe/docker_engine: The system cannot find the file specified. In the default daemon configuratio
  • 原文地址:https://www.cnblogs.com/jz-597/p/14208882.html
Copyright © 2011-2022 走看看