1. 程式人生 > >【NOIP2018普及組】擺渡車

【NOIP2018普及組】擺渡車

@擺渡車@


@題目描述@

有 n 名同學要乘坐擺渡車從人大附中前往人民大學,第 i 位同學在第 ti 分鐘去等車。只有一輛擺渡車在工作,但擺渡車容量可以視為無限大。擺渡車從人大附中出發、把車上的同學送到人民大學、再回到人大附中(去接其他同學),這樣往返一趟總共花費 m 分鐘(同學上下車時間忽略不計)。擺渡車要將所有同學都送到人民大學。
凱凱很好奇,如果他能任意安排擺渡車出發的時間,那麼這些同學的等車時間之和最小為多少呢?
注意:擺渡車回到人大附中後可以即刻出發。

輸入
第一行包含兩個正整數 n,m,以一個空格分開,分別代表等車人數和擺渡車往返一趟的時間。
第二行包含 n 個正整數,相鄰兩數之間以一個空格分隔,第 i 個非負整數 ti代表第 i 個同學到達車站的時刻。
輸出
輸出一行,一個整數,表示所有同學等車時間之和的最小值(單位:分鐘)。

輸入樣例 1
5 1
3 4 4 3 5
輸入樣例 2
5 5
11 13 1 5 5

輸出樣例 1
0
輸出樣例 2
4

輸入輸出樣例 1 說明
同學 1 和同學 4 在第 3 分鐘開始等車,等待 0 分鐘,在第 3 分鐘乘坐擺渡車出發。擺渡車在第 4 分鐘回到人大附中。
同學 2 和同學 3 在第 4 分鐘開始等車,等待 0 分鐘,在第 4 分鐘乘坐擺渡車出發。擺渡車在第 5 分鐘回到人大附中。
同學 5 在第 5 分鐘開始等車,等待 0 分。

輸入輸出樣例 2 說明
同學 3 在第 1 分鐘開始等車,等待 0 分鐘,在第 1 分鐘乘坐擺渡車出發。擺渡車在第 6 分鐘回到人大附中。
同學 4 和同學 5 在第 5 分鐘開始等車,等待 1 分鐘,在第 6 分鐘乘坐擺渡車出發。擺渡車在第 11 分鐘回到人大附中。
同學 1 在第 11 分鐘開始等車,等待 2 分鐘;同學 2 在第 13 分鐘開始等車,等待 0 分鐘。他/她們在第 13 分鐘乘坐擺渡車出發。自此所有同學都被送到人民大學。總等待時間為 4。可以證明,沒有總等待時間小於 4 的方案。

資料規模與約定
對於 10% 的資料,n ≤ 10,m = 1,0 ≤ ti ≤ 100。
對於 30% 的資料,n ≤ 20,m≤ 2,0 ≤ ti ≤ 100。
對於 50% 的資料,n ≤ 500,m ≤ 100,0 ≤ ti ≤ 10^4。
另有 20% 的資料,n ≤ 500,m ≤ 10,0 ≤ ti ≤ 4×10^6。
對於 100% 的資料,n ≤ 500,m ≤ 100,0 ≤ ti ≤ 4×10^6。

@絕對不可能是正解的題解@

搜到了不少的題解,一個比一個強 orz。
這個演算法應該是一個比較容易“想到”的演算法(因為題目中很多的性質都沒有用到)
但是有用到斜率優化……
定義 a [ i ] a[i] 表示第 i 個時刻到達進行等車的人數。
定義 d p [ i ] dp[i] 表示在第 i 個時刻發車,前面的同學最小等待時間之和。
則有:
d p [ i ] = min ( d p [ j ] + ( k = j + 1 k i a [ k ] ( i k ) ) ) ( i j > = m ) dp[i] = \min(dp[j] + (\sum_{k=j+1}^{k\le i}a[k]*(i-k)))(i-j>=m)
拆開得到:
d p [ i ] = min ( d p [ j ] + i ( k = j + 1 k i a [ k ] ) ( k = j + 1 k i a [ k ] k ) ) ( i j > = m ) dp[i] = \min(dp[j] + i*(\sum_{k=j+1}^{k\le i}a[k])-(\sum_{k=j+1}^{k\le i}a[k]*k))(i-j>=m)
c n t [ i ] = j = 1 j i a [ j ] cnt[i]=\sum_{j=1}^{j\le i}a[j] s u m [ i ] = j = 1 j i a [ j ] j sum[i]=\sum_{j=1}^{j\le i}a[j]*j 。這兩貨可以字首和O(n)處理。

則轉移方程式變為:
d p [ i ] = min ( d p [ j ] + i ( c n t [ i ] c n t [ j ] ) ( s u m [ i ] s u m [ j ] ) ) = min ( d p [ j ] + i c n t [ i ] i c n t [ j ] s u m [ i ] + s u m [ j ] ) = min ( ( i c n t [ i ] s u m [ i ] ) + ( d p [ j ] + s u m [ j ] ) i c n t [ j ] ) ( i j > = m ) dp[i] = \min(dp[j] + i*(cnt[i]-cnt[j])-(sum[i]-sum[j]))\\=\min(dp[j] + i*cnt[i]-i*cnt[j]-sum[i]+sum[j])\\=\min( (i*cnt[i]-sum[i]) + (dp[j]+sum[j]) - i*cnt[j]) (i-j>=m)
f ( i ) = ( i c n t [ i ] s u m [ i ] ) , g ( j ) = ( d p [ j ] + s u m [ j ] ) , h ( j ) = c n t [ j ] f(i)=(i*cnt[i]-sum[i]), g(j)=(dp[j]+sum[j]), h(j)=cnt[j]
d p [ i ] = min ( f ( i ) + g ( j ) i h ( j ) ) ( j < = i m ) dp[i]=\min(f(i) + g(j) - i*h(j)) (j<=i-m)

典型的不能再典型的斜率優化式…… i 和 h(j) 還具有單調性……

@程式碼 - [email protected]

雖然當初我去都沒去普及組。
不過普及組(涉嫌)考到斜率優化倒是令我極其感興趣,就寫了一下 qwq。

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef pair<int, ll> pil;
const int INF = (1<<30);
const int MAXN = 4000100;
int cnt[MAXN + 5];
ll sum[MAXN + 5], dp[MAXN + 5];
ll f(int i) {
    return cnt[i]*i - sum[i];
}
ll g(int j) {
    return dp[j]+sum[j];
}
ll h(int j) {
    return cnt[j];
}
double slope(int x, int y) {
	if( h(x) == h(y) ) {
		if( g(x) > g(y) ) return -INF;
		else if( g(x) < g(y) ) return INF;
	}
	else return 1.0*(g(y) - g(x))/(h(y) - h(x));
}
int que[MAXN + 5];
int main() {
    int n, m, x, lim = 0;
    scanf("%d%d", &n, &m);
    for(int i=1;i<=n;i++) {
        scanf("%d", &x);
        cnt[x]++; lim = max(lim, x);
    }
    lim += m;
    for(int i=1;i<=lim;i++) {
        sum[i] = sum[i-1] + 1LL*cnt[i]*i;
        cnt[i] 
            
           

相關推薦

NOIP2018普及擺渡

@擺渡車@ @題目描述@ @絕對不可能是正解的題解@ @程式碼 - [email protected] @看起來比較像正解的題解@ @程式碼 - [email protected] @[email

NOIP2018普及對稱二叉樹

@對稱二叉樹@ @題目描述@ @題解@ @程式碼@ @[email protected] @題目描述@ 一棵有點權的有根樹如果滿足以下條件,則被軒軒稱為對稱二叉樹: 二叉樹;

Luogu 5017 NOIP2018普及T3 擺渡 (斜率優化 + 必要的轉移進行剪枝)

題意:   有 n 名同學要乘坐擺渡車從人大附中前往人民大學,第 i 位同學在第 ti​ 分鐘去 等車。只有一輛擺渡車在工作,但擺渡車容量可以視為無限大。擺渡車從人大附中出發、 把車上的同學送到人民大學、再回到人大附中(去接其他同學),這樣往返一趟

NOIP2018洛谷P5017擺渡DP

題目大意: 題目連結:https://www.luogu.org/problemnew/show/P5017 有 n n

NOIP2017普及賽後心得

ora 特殊 簡單 text 很多 調試 就是 str 格子 我覺得可能今生再也見不到這麽簡單的題目了……甚至有種能AK的錯覺(不 然而考場上腦殼疼了,只剩下310~330。 T4告訴我以後遇到不會的東西一定要早點學…… 題目分析 T1 分數 這次連模擬都不用了,幹脆叫你輸

[jzoj]2018.07.12NOIP普及模擬賽D:解題報告

1.權勢二進位制 題目: 一個十進位制整數被叫做權勢二進位制,當他的十進位制表示的時候只由0或1組成。例如0,1,101,110011都是權勢二進位制而2,12,900不是。 當給定一個n的時候,計算一下最少要多少個權勢二進位制相加才能得到n。 輸入: k組測試資料。 輸出:

[jzoj]2018.07.15NOIP普及模擬賽D:解題報告

目錄: 1.馬農 2.馬語翻譯 3.馬球比賽  4.棋盤遊戲 1.馬農 題目描述: 在觀看完戰馬檢閱之後,來自大草原的兩兄弟決心成為超級“馬農”,專門飼養戰馬。 兄弟兩回到草原,將可以養馬的區域,分為 N*N 的單位面積的正方形, 並實地進行考察,歸納出了每

2018普及-T3 擺渡

題目描述 有 nn 名同學要乘坐擺渡車從人大附中前往人民大學,第 ii 位同學在第 t_it i ​ 分鐘去 等車。只有一輛擺渡車在工作,但擺渡車容量可以視為無限大。擺渡車從人大附中出發、 把車上的同學送到人民大學、再回到人大附中(去接其他同學),這樣往返一趟總共花費mm分鐘(同學上下車

NOIP2016普及魔法陣的解析——一些神奇的列舉優化

題目大意:給定一個序列,要求求出滿足,且的a,b,c,d的數量. 首先這道題可以直接用一個桶,先把所有數塞進這個桶裡. 然後我們可以開始列舉答案. 但我們發現,所以我們可以省去以為的列舉,做到列舉,實測在洛谷上能拿到85分. 到這一步優化的程式碼如下: #inc

2018.10.06NOIP普及模擬賽C

T1 YY 題目描述 最近小h接到命令,要再出一份題目,於是小h馬上陷入了沉思之中,想到了yy曾經出過的一道題目:給出一個超大正整數S,S的位數小於500000,然後找出一個數 n, 使得n

NOIP2018提高D1T2 貨幣系統

文章目錄 題目 思路 題目 題目描述 在網友的國度中共有 n n

NOIP2018普及級別危險係數

時間限制: 1000 ms 空間限制: 131072 KB 題目描述 FJ在一條船上,海上有N(1<=N<=100)島,編號為1..N,現在他的任務是按照一個給定訪問次序A_1,A_2,….A_M去探索這M(2<=M<=10,000)個島嶼,已經

[jzoj]2018.07.11NOIP普及模擬賽D:解題報告

目錄 1.和諧數 2.分數 3.終極數 4.串 1.和諧數 給定一個長度為N的序列a,對於每一個數都可選或不選,把選出的數有序組成一個新的序列b,使b序列的“和諧數”最大。一個序列的和諧數如下定義:對於位置i,如果第奇數次選的則加上bi,偶數次選的則減去bi  注

紀中訓練 day5 NOIP普及模擬賽D 解題報告

目錄 大意 從左到右,問加了一個’p’後一共有幾個noi?(p可以為n,o,i中的一個)長度小於100001 思路 加p之前,noi的個數為每個o之前n的個數*之後i的個數並累加。 加p之後,有三種情況:N,O,I N肯定是放在

2017.08.14NOIP 普及模擬賽C總結

好久沒考好了。。十分尷尬,發誓要考好! 第一題,羊羊整除。 難度:D組第二題~C組第一題。 模擬不多說。 第二題,羊羊吃草。 難度:D組第三題~C組第三題- 二分列舉,淼淼! 第三題,羊羊修路。 最小

2017.04.02NOIP 普及模擬賽C T2:士兵

士兵 題目描述 在Gridland國家,有N個處於不同位置的士兵。該國上的地方都用兩個座標(X,Y)來表示。士兵能進行一次移動,每個士兵都可向上、向下、向左、或向右移動一個單位長,這樣他就能把自己的X或Y改變1或-1。 士兵們想進入一個水平線,彼此靠近,這

NOIP普及2016年模擬考試(11.5)——火柴棒等式

一、火柴棒等式(equation.cpp) 時間限制: 1 Sec  記憶體限制: 128 MB 題目描述 給你n根火柴棍,你可以拼出多少個形如“A+B=C”的等式?等式中的A、B、C是用火柴棍拼

二叉樹的遍歷 &NOIP2001普及& 洛谷 P1030 求先序排列

題目 輸出 image pre ext bubuko 二叉樹 找到 pan 題目鏈接 https://www.luogu.org/problemnew/show/P1030 模板題 先講一下二叉樹的遍歷 二叉樹的遍歷 分類 性質 求法 分為三類:

第二十四屆全國青少年資訊學奧林匹克聯賽NOIP2018普及初賽試題解析(C++語言)

選擇題 1.D 【解析】印表機屬於輸出裝置,它將一些資訊通過印表機打印出來。掃描器,鍵盤,滑鼠屬於輸入裝置。 2.D 【解析】 A,B,C選項的十進位制數值都是 617

洛谷 題解 P5015 標題統計 NOIP2018 普及 T1

stdio.h 理解 iso include %d num || code tdi 沒有人用 scanf("%c", &ch) != EOF 嗎? scanf 和 EOF 會傷心的。 思路:逐個讀入字符,遇到EOF中止,對於每個讀入的字符進行判斷