[差分约束] Topcoder SRM553 Div1 Hard. YamanoteLine

可行的长度肯定是一个区间

约束条件可以建城差分约束系统,那么判无解就是判是否有负环

记一下负环上关于总长度的系数,二分就可以了

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

const int N=1010;

typedef long long ll;

int n,t;

struct Edge{
  int s,t;
  ll k,d;
  Edge(){}
  Edge(int _s,int _t,ll _k,ll _d):s(_s),t(_t),k(_k),d(_d){}
}e[N];

ll dis[N],f[N];

inline pair<int,ll> check(ll x){
  for(int i=0;i<=n;i++) dis[i]=1LL<<60,f[i]=0;
  dis[0]=0;
  ll ret; bool flg;
  for(int i=1;i<=n*n;i++){
    flg=0;
    for(int i=1;i<=t;i++){
      if(dis[e[i].s]==(1LL<<60)) continue;
      if(dis[e[i].t]>dis[e[i].s]+x*e[i].k+e[i].d){
    dis[e[i].t]=dis[e[i].s]+x*e[i].k+e[i].d;
    f[e[i].t]=ret=f[e[i].s]+e[i].k;
    if(dis[e[i].t]<0) return make_pair(0,ret);
    flg=1;
      }
    }
  }
  if(!flg) return make_pair(1,0);
  else return make_pair(0,ret);
}

class YamanoteLine{
public:
  ll howMany(int _n, vector<int> s1, vector<int> t1, vector<int> l1, vector<int> s2, vector<int> t2, vector<int> l2){
    n=_n;
    for(int i=0;i<=n-1;i++) e[++t]=Edge(i+1,i,0,-1);
    for(int i=0;i<s1.size();i++){
      int S=s1[i],T=t1[i],L=l1[i];
      if(S<T) e[++t]=Edge(T,S,0,-L);
      else e[++t]=Edge(T,S,1,-L);
    }
    for(int i=0;i<s2.size();i++){
      int S=s2[i],T=t2[i],L=l2[i];
      if(S<T) e[++t]=Edge(S,T,0,L);
      else e[++t]=Edge(S,T,-1,L);
    }
    e[++t]=Edge(0,n,1,0);
    e[++t]=Edge(n,0,-1,0);
    ll U,D,L,R,mid;
    L=0; R=1LL<<60;
    while(L<=R){
      mid=L+R>>1;
      pair<int,ll> cur=check(mid);
      if(cur.first) D=mid;
      if(cur.second<0 || cur.first) R=mid-1;
      else L=mid+1;
    }
    L=0; R=1LL<<60;
    while(L<=R){
      mid=L+R>>1;
      pair<int,ll> cur=check(mid);
      if(cur.first) U=mid;
      if(cur.second>0 || cur.first) L=mid+1;
      else R=mid-1;
    }
    if(U==(1LL<<60)) return -1;
    return max(U-D+1,0LL);
  }

};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值