[NOI2019]回家路線

C202044zxy發表於2020-10-04

一、題目

點此看題

二、解法

首先可以用暴力 d p dp dp艹過去,設 d p [ i ] [ j ] dp[i][j] dp[i][j]為到了 i i i點的時間是 j j j的最小花費,由於時間是單向流逝的,我們可以先把邊按出發時間排序,用邊轉移,列舉到達出發點的時間 j j j
d p [ y [ i ] ] [ q [ i ] ] = d p [ x [ i ] ] [ j ] + c o s t ( p [ i ] − j ) dp[y[i]][q[i]]=dp[x[i]][j]+cost(p[i]-j) dp[y[i]][q[i]]=dp[x[i]][j]+cost(p[i]j)但是人總要追求正解,設 d p [ i ] dp[i] dp[i]為正好走過第 i i i條邊的最小花費,轉移列舉上一次走過的邊 j j j,轉移需要滿足條件: q j ≤ p i , y [ j ] = x [ i ] q_j\leq p_i,y[j]=x[i] qjpi,y[j]=x[i],方程式如下:
d p [ i ] = d p [ j ] + A ( p [ i ] − q [ j ] ) 2 + B ( p [ i ] − q [ j ] ) + C dp[i]=dp[j]+A(p[i]-q[j])^2+B(p[i]-q[j])+C dp[i]=dp[j]+A(p[i]q[j])2+B(p[i]q[j])+C這種平方轉移好像能推斜率式,設轉移點 j > k j>k j>k,且 j j j決策點優(給結論):
d p [ j ] + A q [ j ] 2 − B q [ j ] − d p [ k ] − q [ k ] 2 + B q [ k ] q [ j ] − q [ k ] < 2 A p [ i ] \frac{dp[j]+Aq[j]^2-Bq[j]-dp[k]-q[k]^2+Bq[k]}{q[j]-q[k]}<2Ap[i] q[j]q[k]dp[j]+Aq[j]2Bq[j]dp[k]q[k]2+Bq[k]<2Ap[i]畫個圖可以發現斜率是單調遞增的,但是現在的轉移順序問題還是有些蛋疼,觀察我們轉移需要的兩個條件,我們可以先滿足第二個條件,也就是維護 n n n個凸包,詢問的時候到對應的凸包裡面查詢。那第一個條件怎麼辦?我們轉移的時候先列舉邊的出發時間,插入凸包的時候只插入結束時間不超過它的,這樣凸包裡的東西就滿足第一個條件了。

時間複雜度 O ( m ) O(m) O(m),凸包需要 v e c t o r \tt vector vector

#include <cstdio>
#include <vector>
#include <queue>
using namespace std;
const int M = 200005;
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,m,ans,A,B,C,x[M],y[M],p[M],q[M],h[M],t[M],dp[M];
vector<int> Q[M],a[M];queue<int> b[M];
int up(int j,int k) 
{
	return dp[j]+A*q[j]*q[j]-B*q[j]-dp[k]-A*q[k]*q[k]+B*q[k];
}
int down(int j,int k)
{
	return q[j]-q[k];
}
void ins(int u,int i)//在u凸包插入i 
{
	while(h[u]<t[u] && 1ll*up(Q[u][t[u]],Q[u][t[u]-1])*down(i,Q[u][t[u]])>=1ll*up(i,Q[u][t[u]])*down(Q[u][t[u]],Q[u][t[u]-1]))
		t[u]--;
	while(Q[u].size()<t[u]+3) Q[u].push_back(0);
	Q[u][++t[u]]=i;
}
void fuck(int u,int i)//在u凸包中把不滿足i的艹出去
{
	while(h[u]<t[u] && 1ll*up(Q[u][h[u]+1],Q[u][h[u]])<=2ll*A*p[i]*down(Q[u][h[u]+1],Q[u][h[u]]))
		h[u]++;
} 
signed main()
{
	n=read();m=read();A=read();B=read();C=read();
	for(int i=1;i<=m;i++)
	{
		x[i]=read();y[i]=read();
		p[i]=read();q[i]=read();
		a[p[i]].push_back(i);
	}ans=1e18;
	for(int i=2;i<=n;i++)
		t[i]=-1;
	Q[1].push_back(0);
	for(int T=0;T<=1000;T++)
	{
		while(!b[T].empty())
		{
			int u=b[T].front();b[T].pop();
			ins(y[u],u);
		}
		for(int i=0;i<a[T].size();i++)
		{
			int u=a[T][i];
			if(h[x[u]]>t[x[u]]) continue;
			fuck(x[u],u);
			int j=Q[x[u]][h[x[u]]];
			dp[u]=dp[j]+A*(p[u]-q[j])*(p[u]-q[j])+B*(p[u]-q[j])+C;
			b[q[u]].push(u);
			if(y[u]==n) ans=min(ans,dp[u]+q[u]); 
		}
	}
	printf("%d\n",ans);
}
/*
dp[i]=min(dp[j]+A(pi-qj)^2+B(pi-qj)+C) x[i]=y[j]
j在後,j優 
dp[j]+A(pi-qj)^2+B(pi-qj)<dp[k]+A(pi-qk)^2+B(pi-qk)
dp[j]+A(-2piqj+qj^2)-Bqj<dp[k]+A(-2piqk+qk^2)-Bqk
dp[j]+Aqj^2-Bqj-dp[k]-qk^2+Bqk<2Api(qj-qk)
*/

相關文章