【51nod 1340】地鐵環線

題目

有一個地鐵環線,環線中有N個站臺,標號爲0,1,2,...,N-1。這個環線是單行線,一共由N條有向邊構成,即從0到1,1到2,..k到k+1,...,N-2到N-1,N-1到0各有一條邊。定義兩站之間的距離,站a與站b間的距離dis(a,b)指從a站出發沿着單行線的邊走到達b時所通過的所有長度,即dis(a,b)=dis(a,a+1)+dis(a+1,a+2)+..+dis(k,k+1 mod N)..+dis(b-1,b)。提示一下,a>b時路徑爲a->a+1->...N-1->0->...->b,注意這是個環線。有兩我的向你提供了一些關於環線的信息: 其第一我的提供了M1條信息,每條信息:站點Ai到站點Bi的距離至少是Di,即dis(Ai,Bi)>=Di; 而第二我的提供了M2條信息,每條信息:站點ai到站點 bi的距離最可能是di ,即dis(ai,bi)<=di 。 另外,已知相鄰兩站的距離至少是1千米,且全部站點間的距離都是整數千米。 請根據以上的信息計算這條地鐵環線的總長有多少種可能,並輸出這個數量,若是若是有長度有無數種可能輸出-1.ios

分析

看到一堆不等式的信息,首先想到就是差分約束, 當總長度s肯定時,咱們就能夠作差分約束,判斷有無負環來判斷是否合法 連邊數組

對於dis(Ai,Bi)>=Di,
    	若是Ai<Bi,Bi向Ai連一條的邊,邊權爲-Di
    	若是Ai>Bi,Bi向Ai連一條的邊,邊權爲s-Di
    對於dis(ai,bi)<=di,
    	若是ai<bi,ai向bi連一條的邊,邊權爲Di
    	若是ai>bi,ai向bi連一條的邊,邊權爲-s+Di
	相鄰點距離至少爲1,相似第一種狀況

而後用Bellman_Ford,在進行n-1次鬆弛操做後, 若是依然能夠進行鬆弛操做,即存在邊(a,b),dis[a]+v(a,b)<dis[b],就存在負環,則不合法。 反之。函數

考慮如何求方案數, 咱們發現每條邊的邊權個一次函數, 進行n-1次鬆弛操做,因而對於每一個點的每種s的係數k記錄$dis[x][k]$,表示當走到x時,s的係數爲k的最小值爲$dis[x][k]$ 而後對於每一條邊(a,b)維護一個單調棧,表示每一段s的值域是由s的哪一個係數控制(詳細見程序) 而後對於一段某一段s的值域的,代入s,若是a點的函數值+(a,b)>b點的函數值,則這一段值域對於這一條邊是合法的。用個前綴和數組,這一段值域的合法邊數加1. 當一段值域的合法邊數爲總邊數時,這段值域的s都合法,ans加上個數。spa

#include <cmath>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
#include <bitset>
#include <set>
#include <vector>
const int mo=1e9+7;
const int N=55;
using namespace std;
int T,n,m1,m2,tot,num,vv;
long long dis[N][N*2],inf;
struct list
{
	long long x,v;
}lis[N*N*N*2];
struct line
{
	long long l,r,k,b;
	long long f(long long x)
	{
		return k*x+b;
	}
}s1[N*N*N*2],t1[N*N*N*2];
long long min(long long x,long long y)
{
	return x<y?x:y;
}
long long max(long long x,long long y)
{
	return x>y?x:y;
}
long long up(long long tb,long long tk)
{
	if(tk<0) tk=-tk,tb=-tb;
	long long tt=tb/tk;
	return tt+(tt*tk<tb);
}
long long down(long long tb,long long tk)
{
	if(tk<0) tk=-tk,tb=-tb;
	long long tt=tb/tk;
	return tt-(tt*tk>tb);
}
void push(line *a,int &num,line t)
{
	while(num && t.f(a[num].l)<=a[num].f(a[num].l)) num--;
	if(num) t.l=down(-(a[num].b-t.b),a[num].k-t.k)+1,a[num].r=t.l-1;
	a[++num]=t;
}
void put(long long l,long long r)
{
	lis[++num]=(list){l,1};
	lis[++num]=(list){r+1,-1};
}
void check(line s1,line t1)
{
	long long l=max(s1.l,t1.l),r=min(s1.r,t1.r);
	if(l>r) return;
	line t={0,0,s1.k-t1.k,s1.b-t1.b};
	if(t.f(l)<0 && t.f(r)<0) return;
	put(t.f(l)>=0?l:up(-t.b,t.k),t.f(r)>=0?r:down(-t.b,t.k));
}
struct edge
{
	long long x,y,v,k;
	void BF()
	{
		for(int i=0;i<=2*n;i++)
			if(i+k>=0 && i+k<=2*n) dis[y][i+k]=min(dis[y][i+k],dis[x][i]+v);
	}
	void calc()
	{
		int n1=0,n2=0;
		for(int i=2*n;i>=0;i--)
		{
			if(dis[x][i]<inf/2) push(s1,n1,(line){n,inf,i+k-n,dis[x][i]+v});
			if(dis[y][i]<inf/2) push(t1,n2,(line){n,inf,i-n,dis[y][i]});
		}
		for(int k1=1,k2=1;k1<=n1 && k2<=n2;s1[k1].r<=t1[k2].r?k1++:k2++) check(s1[k1],t1[k2]);
	}
}E[N<<2];
bool cmp(list x,list y)
{
	return x.x<y.x;
}
int main()
{
	for(scanf("%d",&T);T--;)
	{
		scanf("%d%d%d",&n,&m1,&m2);
		memset(dis,1,sizeof(dis));
		memset(lis,0,sizeof(lis));
		inf=dis[0][0],dis[0][n]=0;
		tot=0;
		for(int i=0;i<n;i++) E[++tot]=(edge){(i+1)%n,i,-1,i==n-1};
		long long x,y,v;
		for(int i=1;i<=m1;i++)
		{
			scanf("%lld%lld%lld",&x,&y,&v);
			E[++tot]=(edge){y,x,-v,(x>y)};
		}
		for(int i=1;i<=m2;i++)
		{
			scanf("%lld%lld%lld",&x,&y,&v);
			E[++tot]=(edge){x,y,v,-(x>y)};
		}
		for(int i=1;i<n;i++)
			for(int j=1;j<=tot;j++) E[j].BF();
		for(int i=1;i<=tot;i++) E[i].calc();
		sort(lis+1,lis+1+num,cmp);
		lis[num+1]=(list){inf+1,0};
		long long sum=0,ans=0;
		for(int i=1;i<=num;i++) ans+=((sum+=lis[i].v)==tot)*(lis[i+1].x-lis[i].x);
		printf("%lld\n",ans>=inf/4?-1:ans);
	}
}
相關文章
相關標籤/搜索