洛谷AT2342 Train Service Planning(思惟,動態規劃,珂朵莉樹)

洛谷題目傳送門c++

神仙思惟題仍是要寫點東西纔好。優化

創建數學模型

這種很抽象的東西沒有式子描述一下顯然是下不了手的。
由於任何位置都以\(k\)爲週期,因此咱們只用關心一個週期,也就是如下數都在膜\(k\)意義下。
\(a_i\)表示\(i\)號區間長度;
對於上行列車(\(0\rightarrow n\))設\(p_0\)表示出發時刻,\(p_i(i\ge1)\)表示在\(i\)站停靠時間;
對於下行列車(\(0\leftarrow n\))設\(-q_0\)表示到站時刻,\(q_i(i\ge1)\)表示在\(i\)站停靠時間;
(轉化成\(-q_0\)是爲了後面表示方便)
用大寫字母\(A,P,Q\)分別表示它們的前綴和。
若是某區間\(b_i=1\),則兩列車的行駛時間區間不交,即
\[(P_{i-1}+A_{i-1},P_{i-1}+A_i)\cap(-Q_{i-1}-A_i,-Q_{i-1}-A_{i-1})=\emptyset\]
區間不交即端點不被包含,能夠列出不等式(被取模了因此看着比較奇怪)
\[\begin{cases}P_{i-1}+A_i\le-Q_{i-1}-A_i\\P_{i-1}+A_{i-1}\ge-Q_{i-1}-A_{i-1}\end{cases}\]
\(x=P_{i-1}+Q_{i-1}\),移項,解得\(x\in[-2A_{i-1},-2A_i]\)
由於\(P,Q\)是遞增的,因此咱們的問題變成了:
有若干個限制區間\([l_i,r_i]\),你手頭有一個數\(x\),初值任選,每次能夠加一個非負整數使它落在區間內,求最少總共加多少能知足限制。spa

優化求解

考慮這樣一個貪心的決策過程:
假設咱們知道當前的\(x\),咱們須要統計它最少總共被加了多少。咱們看上一個限制區間。
若是\(x\)被上一個區間包含,那麼咱們看上上個區間。
若是\(x\)沒有被上一個區間包含,則\(x\)從區間的右端點加過來的代價最小,咱們繼續對上上個區間的右端點進行決策。
發現咱們決策的中間狀態只和區間右端點有關,因此咱們設\(f_i\)表示決策到第\(i\)個區間時,\(x=r_i\)的最小代價。
咱們對於每一個值維護最後一個沒有包含這個值的區間編號,每次取出\(r_i\)對應的編號(記爲\(j\)),用\(f_j+r_i-r_j\)更新\(f_i\),並將\([r_i+1,l_i-1]\)的編號所有設爲\(i\)
最後把全部的\(l_i\)丟進去查一下取個\(\min\)加上\(2A_n\)就是答案。
由於是區間設置因此能夠珂朵莉樹維護,不用離散化,由於隨機數據的編號段數不會太大因此平均狀況下跑得比線段樹還快。
特判:若是\(2a_i>k\)那麼puts("-1")code

#include<bits/stdc++.h>
#define LL long long
#define R register int
#define G if(++ip==ie)if(fread(ip=buf,1,SZ,stdin))
using namespace std;
const int SZ=1<<19,N=1e5+9;
char buf[SZ],*ie=buf+SZ,*ip=ie-1;
inline int in(){
    G;while(*ip<'-')G;
    R x=*ip&15;G;
    while(*ip>'-'){x*=10;x+=*ip&15;G;}
    return x;
}
int k,l[N],r[N];LL f[N];bool b[N];
struct Node{
    int r;mutable int v;
    inline Node(R a,R b=0):r(a),v(b){}
    inline bool operator<(const Node&a)const{return r<a.r;}
};
typedef set<Node>::iterator IT;
set<Node>s;
inline IT Split(R p){
    IT i=s.lower_bound(Node(p));
    return i->r!=p?s.insert(Node(p,i->v)).first:i;
}
inline void Set(R l,R r,R v){
    if(l>r)return;
    IT il=Split(l-1),ir=Split(r);
    ir->v=v;s.erase(++il,ir);
}
inline LL Calc(R p){
    R j=s.lower_bound(Node(p))->v;
    return j?f[j]+(p-r[j]+k)%k:0;
}
int main(){
    R n=in();LL k=::k=in(),a=0,a1=0,ans=1e18;
    s.insert(Node(-1));
    s.insert(Node(k-1));
    for(R i=1;i<=n;++i){
        a1=a;a+=in();
        if(!(b[i]=in()&1))continue;
        if(2*(a-a1)>k)return puts("-1"),0;
        l[i]=(-2*a1%k+k)%k;r[i]=(-2*a%k+k)%k;
        f[i]=Calc(r[i]);
        if(l[i]>r[i])Set(r[i]+1,l[i]-1,i);
        else Set(0,l[i]-1,i),Set(r[i]+1,k-1,i);
    }
    for(R i=1;i<=n;++i)
        if(b[i])ans=min(ans,Calc(l[i]));
    cout<<ans+2*a<<endl;
    return 0;
}
相關文章
相關標籤/搜索