题解:P15011 [UOI 2019 II Stage] 土豆
源点向每个城市连
直接网络流应该是跑不过的,考虑 HALL 定理:
假设
G=(X,Y,E) 是二分图,且|X|\le|Y| 。对于任何W\subseteq X ,记NG(W) 为图G 中所有与W 中的顶点相邻的顶点集合。那么,X 完美匹配存在,当且仅当|W|\le NG(|W|) 对于所有W\subseteq X 都成立。
那二分
constexpr int N=100010,K=20,P=262154;
int a[N],pos[K],cap[K],mask[N];
ll dis[K][N];
ll l[P],r[P];
int main(int argc,char** argv)
{
if(argc==3)freopen(argv[1],"r",stdin),freopen(argv[2],"w",stdout);
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int n,m,k;
cin>>n>>m>>k;
vector<vector<pair<int,int>>>g(n+1);
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=m;i++)
{
int x,y,z;
cin>>x>>y>>z;
g[y].push_back({x,z});
}
for(int i=1;i<=k;i++)cin>>pos[i]>>cap[i];
auto dijkstra=[&](int s,ll* dis)
{
priority_queue<pair<ll,int>,vector<pair<ll,int>>,greater<pair<ll,int>>>pq;
fill(dis+1,dis+n+1,inf<ll>);
vector<char>vis(n+1,0);
dis[s]=0;
pq.push({dis[s],s});
while(!pq.empty())
{
auto[d,x]=pq.top();
pq.pop();
if(vis[x])continue;
vis[x]=1;
for(auto[y,w]:g[x])
if(dis[y]>dis[x]+w)
pq.push({dis[y]=dis[x]+w,y});
}
};
for(int i=1;i<=k;i++)dijkstra(pos[i],dis[i]);
auto sosdp=[&](int n,ll* f)
{
for(int i=0;i<n;i++)
for(int j=0;j<1<<n;j++)
if(j>>i&1)
f[j]+=f[j^1<<i];
};
for(int mask=0;mask<1<<k;mask++)
for(int i=1;i<=k;i++)
if(mask>>(i-1)&1)
r[mask]+=cap[i];
auto check=[&](ll t)
{
fill(l,l+(1<<k),0);
for(int i=1;i<=n;i++)
{
int mask=0;
for(int j=1;j<=k;j++)
if(dis[j][i]<=t)
mask|=1<<(j-1);
l[mask]+=a[i];
}
sosdp(k,l);
for(int mask=0;mask<1<<k;mask++)if(l[mask]>r[mask])return false;
return true;
};
ll l=0,r=inf<ll>-10,ans=-1;
while(l<=r)
{
ll mid=(l+r)>>1;
if(check(mid))ans=mid,r=mid-1;
else l=mid+1;
}
cout<<ans;
return 0;
}