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;
    }
    
  • 相关阅读:
    最艰难的采访IT公司ThoughtWorks代码挑战——FizzBuzzWhizz游戏
    SQL Server 存储字符数较大字段的问题
    c# var的含义与用法
    ListBox和ComboBox绑定数据简单例子
    “C# 未在本地计算机上注册microsoft.Jet.OLEDB.12.0”的解决方案
    [转] c# 操作Word
    C++ Regsvr32订购具体解释
    数字计算的有序排列的号码出现二分法
    合作信息处理模型
    内存四个领域,变量声明和定义,注册,c内联汇编,auto,堆,不变,静态变量
  • 原文地址:https://www.cnblogs.com/jz-597/p/14208882.html
Copyright © 2011-2022 走看看