1. 程式人生 > >簡單題

簡單題

while lib != ace 貪心 負數 uri reg 加油站

https://www.zybuluo.com/ysner/note/1225266

題面

\(n\)個加油站,第\(i\)\(i+1\)個加油站距離為\(d_i\),車遇\(i\)站自動加\(w_i\)油。現有\(k\)油量可分配到各加油站中,來增大各站\(w_i\)。有一任務,即在油量\(>0\)的前提下,從\(l\)站到\(r\)站,再將自帶油量清\(0\),從\(r\)站到\(l\)站。問每個點在完成任務的前提下,最多能走到右邊哪個站?

  • \(8pts\ n\leq1000\)
  • \(31pts\ n\leq20000\)
  • \(100pts\ n\leq10^6\)

時限\(5s\)

解析

\(8pts\)算法

首先顯然有個貪心,就是從左向右走能不加油盡量不加油
正確性顯然。與其把油量都堆在開頭,不如使油量盡量靠後,這樣才能更有助於從右往左,減少卡殼時所需油量。
然後我沒看出來的是,從右往左可以直接在右端加上所有油
因為此時油加的位置沒有其它附加影響了。

於是枚舉每個點,枚舉它能到的最右點,檢驗它是否能到。復雜度\(O(n^3)\)

\(39pts\)算法

註意到答案不具有單調性
並不能說,上個點能達到最右點,這個點也一定能達到最右點。
因為受到出發點油量的影響。假如上個點油量特別大,而這個點特別小呢。

其實我們往右跑時可以同時兼顧向右時對可分配油量的需求,及向左時對可分配油量的需求

枚舉左端點,然後一個勁地向右跑,該加油時就加油,直到可分配油量被耗完為止。這樣保證能從左向右。

在此過程中,實時維護到當前點往返整個過程所需油量\(had\),如果往右跑的過程要加油\(oil\)\(had+=oil\)。同時統計該段從右向左的油量需要(\(w[j]-d[j]\)),不需要、\(had\)可減,需要、\(had\)可加。(\(d[j]\)表示從\(j-1\)號站到\(j\)號站的距離)

顯然如果\(had\)最大時油量還不為負,整個過程就一定合法,也就能走到該段右端點。而如果現在的\(had\)與剩余油量之和大於等於\(max\)就說明從右到左油量到不了負數,該答案合法。
復雜度\(O(n^2)\)
我覺得還是看代碼清楚些

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define re register
#define il inline
#define ll long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define fp(i,a,b) for(re int i=a;i<=b;i++)
#define fq(i,a,b) for(re int i=a;i>=b;i--)
using namespace std;
const int N=1e6+100;
ll n,k,d[N],ans,w[N];
il ll gi()
{
  re ll x=0,t=1;
  re char ch=getchar();
  while(ch!=‘-‘&&(ch<‘0‘||ch>‘9‘)) ch=getchar();
  if(ch==‘-‘) t=-1,ch=getchar();
  while(ch>=‘0‘&&ch<=‘9‘) x=x*10+ch-48,ch=getchar();
  return x*t;
}
int main()
{
  freopen("simple.in","r",stdin);
  freopen("simple.out","w",stdout);
  n=gi();k=gi();
  fp(i,2,n) d[i]=gi();
  fp(i,1,n) w[i]=gi();
  fp(i,1,n)
    {
      re ll had=0,now=w[i],res=k,mx=-1e18;ans=i;
      fp(j,i+1,n)
      {
    if(d[j]>now)
      if(d[j]-now<=res) res-=d[j]-now,had+=d[j]-now,now=0;
      else break;
    else now-=d[j];
        mx=max(mx,had);
        now+=w[j];had+=w[j]-d[j];
        if(had+res>=mx) ans=j;
      }
      printf("%lld ",ans);
    }
  puts("");
  fclose(stdin);
  fclose(stdout);
  return 0;
}

簡單題