Hero_of_Someone

[NOIP2011] 观光公交




设这几个东西:

  1. \(t[i]\),最晚到达 \(i\) 站的人到达的时间;
  2. \(arrive[i]\),车到达 \(i\) 站的时间,显然 \(arrive[i]=max(arrive[i-1],t[i-1])+D[i-1]\)

所以要求的答案就是:\(\sum arrive[target[i]]-reach[i]\)\(reach[i]\)\(i\)到站的时间
当我们考虑到加速器的时候,对于一个站,当 \(arrive[i]<=t[i]\) 时,前面不管用了多少个加速器都不会影响到后面的时间,所以我们再设这样一个东西:\(f[i]\)为,在 \(i\) 这个站用了加速器后能够影响到的 \(i\) 后面最远的站,当 \(arrive[i]<=t[i]\) 时,\(f[i]=i+1\),否则,\(f[i]=f[i+1]\)。所以我们在 \(i\) 站用一个加速器,就会使得答案减少 \(S[f[i]]-S[i]\) ,其中,\(S[i]\)为在 \(i\) 站下车的人数的前缀和,所以我们只需要每次在一个使得 \(S[f[i]]-S[i]\) 最大的 \(i\) 上放一个加速器并实时更新一下 \(arrive[i]\)\(f[i]\) 就好了

//made by Hero_of_Someone
#include<iostream>
#include<cstdio>
#include<cstdlib>
#define N (1010)
#define RG register
using namespace std;
inline int gi(){ RG int x=0,q=1; RG char ch=getchar(); while( ( ch<'0' || ch>'9' ) && ch!='-' ) ch=getchar();
  if( ch=='-' ) q=-1,ch=getchar(); while(ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); return q*x; }

int n,m,k,D[N],ret;
int t[N],arrive[N],S[N],f[N];

void init(){
  n=gi(),m=gi(),k=gi();
  for(RG int i=1;i<n;i++) D[i]=gi();
  for(RG int i=1;i<=m;i++){
    int reach=gi(),outset=gi(),target=gi();
    ret-=reach;
    t[outset]=max(t[outset],reach);
    S[target]++;
  }
  for(RG int i=1;i<=n;i++)
    arrive[i]=max(arrive[i-1],t[i-1])+D[i-1];
  for(RG int i=1;i<=n;i++) S[i]+=S[i-1];
}

void work(){
  while(k){
    f[n]=f[n-1]=n;
    for(RG int i=n-2;i;i--)
      if(arrive[i+1]<=t[i+1]) f[i]=i+1;
      else f[i]=f[i+1];
    int Max=0,s;
    for(RG int i=1;i<n;i++)
      if(S[f[i]]-S[i]>Max&&D[i])
    Max=S[f[i]]-S[i],s=i;
    if(!Max) break; D[s]--; k--;
    for(RG int i=1;i<=n;i++)
      arrive[i]=max(arrive[i-1],t[i-1])+D[i-1];
  }
  for(RG int i=1;i<=n;i++) ret+=arrive[i]*(S[i]-S[i-1]);
  printf("%d\n",ret);
}

int main(){ init(); work(); return 0; }
posted @ 2017-11-08 19:39 蓝甘冰露 阅读(...) 评论(...) 编辑 收藏