1. 程式人生 > 其它 >【做題記錄】[NOIP2011 提高組] 觀光公交

【做題記錄】[NOIP2011 提高組] 觀光公交

P1315 [NOIP2011 提高組] 觀光公交

我們想在 \(k\) 次加速每一次都取當前最優的方案加速。

考慮怎樣計算對於每一條邊如果在當前情況下使用加速器能夠使答案減少的大小。

如果當前到達某個點時已經有人在等待了,那麼加速這個點以前的邊能夠讓這個點下車的人距離減少,而對於仍舊在車上的沒有貢獻。

如果到達這個點時車還需要等待人,那麼加速之前的的邊對車上人的影響會在以後的點(直至這些人下車時)再會計算,而能夠讓在這個點下車的人距離減少。

綜上,我們發現減少一條邊的距離會使在這個點下車的人距離減少,這個貢獻保留到人等車的那一刻,所以我們就可以在 \(k\) 次加速每次處理到達這個點的時間與最後一個人到達的時間,到這取最大值即可。

#define Maxn 10005
int n,m,k,ans;
int Last[Maxn],cntup[Maxn],cntdown[Maxn],arr[Maxn],d[Maxn];
int s[Maxn],t[Maxn],x[Maxn];
int main()
{
	 n=rd(),m=rd(),k=rd();
	 for(int i=2;i<=n;i++) d[i]=rd();
	 for(int i=1;i<=m;i++)
	 {
	 	 x[i]=rd(),s[i]=rd(),t[i]=rd();
	 	 cntup[s[i]]++,cntdown[t[i]]++;
	 	 Last[s[i]]=max(Last[s[i]],x[i]);
	 	 ans-=x[i];
	 }
	 while(k--)
	 {
	 	 for(int i=1;i<=n;i++)
	 	 	 arr[i]=max(Last[i],arr[i-1]+d[i]);
	 	 int hav=0,MAX=0,pos=0;
	 	 for(int i=n;i>=2;i--)
	 	 {
	 	 	 if(arr[i]==Last[i]) hav=cntdown[i];
	 	 	 else
	 	 	 {
	 	 	 	 hav+=cntdown[i];
	 	 	 	 if(d[i] && hav>MAX) MAX=hav,pos=i;
			 }
		 }
		 if(pos) d[pos]--;
		 else break;
	 }
	 for(int i=1;i<=n;i++)
	 	 arr[i]=max(Last[i],arr[i-1]+d[i]),ans+=cntdown[i]*(arr[i-1]+d[i]);
	 printf("%d\n",ans);
	 return 0;
}