【jzoj3773】【NOI2015模拟8.15】【小 P 的烦恼】【动态规划】

xiaoxiao2021-02-28  84

题目大意

小 P 最近遇上了大麻烦,他的高等代数挂科了。于是他只好找高代老师求情。善良的高代老师答应不挂他,但是要求小 P 帮助他一起解决一个难题。

问题是这样的,高代老师近期要组织班上同学一起去漂流,漂流可以看做是在一张 n 个点 m 条边的有向无环图上进行的,点编号从 0 到 n-1 ,表示景点; 边是连接各景点的一定长度的河道。同时,定义编号为 s 是起点而 t 是终点。我们不妨把从 s 点到 t 点不论走什么样的路径都需要经过的边称为桥, 这些桥由于地势险要所以是危险的。现在高代老师有两条长度为 l 的安全绳,他希望用这两条安全绳覆盖尽可能长的桥,使得他们通过的桥的长度之和尽量短。

解题思路

先拓扑排序,求出每个点到t的dis,每个点到s,到t路径数f,g并取模,可以发现一条边u->v是桥当且仅当f[u]*g[v]==f[t]。找出的桥边一定在s到t的路径上,对dis排序并将相连的桥边合并在一起进行dp。

设f[i][0,1,2]表示处理到第i段桥使用了j条绳的桥的最短长度,转移使用二分求出最多能覆盖到哪里并转移,注意可以两条绳连在一起用。

code

#include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #define LF double #define LL long long #define ULL unsigned LL #define fo(i,j,k) for(LL i=j;i<=k;i++) #define fd(i,j,k) for(LL i=j;i>=k;i--) #define fr(i,j) for(LL i=begin[j];i;i=next[i]) using namespace std; LL const mn=1e5+9,mm=2*1e5+9,mo=1e9+7,inf=1e18+7; LL T,n,m,s,t,L,gra,begin[mn],u[mm],v[mm],w[mm],to[mm],len[mm],next[mm],dis[mn],du[mn],q[mn],f[mn],g[mn],F[mn][3],S[mn]; LL max(LL x,LL y){return (x>y)?x:y;} LL min(LL x,LL y){return (x<y)?x:y;} void insert(LL u,LL v,LL w){ to[++gra]=v; len[gra]=w; next[gra]=begin[u]; begin[u]=gra; } struct rec{ LL u,v; }; rec a[mm]; bool cmp(rec x,rec y){ return dis[x.u]>dis[y.u]; } int main(){ freopen("d.in","r",stdin); freopen("d.out","w",stdout); scanf("%lld",&T); fo(cas,1,T){ scanf("%lld%lld%lld%lld%lld",&n,&m,&s,&t,&L);s++;t++; gra=0; fo(i,1,n)begin[i]=du[i]=0; fo(i,1,m){ scanf("%lld%lld%lld",&u[i],&v[i],&w[i]);u[i]++;v[i]++; insert(u[i],v[i],w[i]); du[v[i]]++; } LL ti=0; fo(i,1,n)if(!du[i])q[++ti]=i; fo(i,1,n){ LL p=q[i]; fr(j,p){ du[to[j]]--; if(!du[to[j]])q[++ti]=to[j]; } } fo(i,1,n)dis[i]=inf; dis[t]=0; fd(i,n,1){ LL p=q[i]; fr(j,p)dis[p]=min(dis[p],dis[to[j]]+len[j]); } fo(i,1,n)f[i]=g[i]=0; f[s]=1; fo(i,1,n){ LL p=q[i]; fr(j,p)f[to[j]]=(f[to[j]]+f[p])%mo; } g[t]=1; fd(i,n,1){ LL p=q[i]; fr(j,p)g[p]=(g[p]+g[to[j]])%mo; } LL tmp=0; fo(i,1,m)if(f[t]==f[u[i]]*g[v[i]]%mo) a[++tmp].u=u[i],a[tmp].v=v[i]; sort(a+1,a+tmp+1,cmp); LL tm2=0; fo(i,1,tmp)if(a[i].u!=a[i-1].v){ a[++tm2].u=a[i].u; a[tm2].v=a[i].v; }else a[tm2].v=a[i].v; tmp=tm2; fo(i,1,tmp){ S[i]=dis[a[i].u]-dis[a[i].v]; fo(j,0,2){ F[i][j]=F[i-1][j]+S[i]; if(j){ LL l=1,r=i; while(l!=r){ LL md=(l+r+1)/2; if(dis[a[md].u]-dis[a[i].v]<L)r=md-1; else l=md; } F[i][j]=min(F[i][j],F[l-1][j-1]+max(min(dis[a[l].u]-dis[a[i].v]-L,S[l]),0)); if(l+1<=i)F[i][j]=min(F[i][j],F[l][j-1]); if(j==2){ LL l=1,r=i; while(l!=r){ LL md=(l+r+1)/2; if(dis[a[md].u]-dis[a[i].v]<L*2)r=md-1; else l=md; } F[i][j]=min(F[i][j],F[l-1][j-2]+max(min(dis[a[l].u]-dis[a[i].v]-L*2,S[l]),0)); if(l+1<=i)F[i][j]=min(F[i][j],F[l][j-2]); } } } } LL ans=inf; fo(i,0,2)ans=min(ans,F[tmp][i]); if(f[t])printf("%lld\n",ans); else printf("-1\n"); } return 0; }
转载请注明原文地址: https://www.6miu.com/read-53672.html

最新回复(0)