NOIP2016 提高二試 蚯蚓 題解
根據題意,每次都選取長度最長的蚯蚓將其切開,這不由的讓我們想到了大頂堆和優先佇列(其實優先佇列的實質也是堆),但這種做法的複雜度卻達到了O[M*log(N+M)],將題目最大資料規模代入約為1.4億,這顯然無法在1s的時間內通過。
那還有什麼更好的演算法能讓我們快速的在一組資料中找到一個最大值呢?
假設存在長度分別為a[ i ]和a[ j ]的蚯蚓,令其滿足i<j且a[ i ]>=a[ j ](可以認為a[]陣列是單調非遞增的)。
因為a[ i ]>=a[ j ]
所以a[ i ]*p>=a[ j ]*p (p>=0, p∈R)
所以int(a[ i ]*p)>=int(a[ j ]*p) (int()相當於下取整)
所以{ a[ i ] - int(a[ i ]*p) } >= { a[ j ] - int(a[ j ]*p }
也就是說,如果儲存待切蚯蚓長度的陣列a[]滿足單調非遞增,則其按題意產生的左右兩段蚯蚓的長度一定也能夠按被切的順序單調非遞增。分析到這裡,有沒有看出什麼貓膩呢?沒錯,我們可以用單調佇列解決!
我們開三個佇列(在這我就不用STL了,用陣列模擬)a[], x[], y[],分別儲存原始蚯蚓長度(即讀入的)、被切為左段的長度、被切為右段的長度。當然a[]是預先進行非遞減排序的。這樣,每1秒從三個佇列選取值最大的隊頭出隊,將其“切”成兩段後再分別從隊尾存入x[]和y[]。
程式碼如下:(max函式返回的是三個佇列中最大隊頭的值,同時對隊頭最大的對列進行出隊操作。)
const int MaxN = 100000+2;
const int MaxM = 7000000+2;
int a[MaxN], front_a, back_a;
int x[MaxN+MaxM], front_x, back_x;
int y[MaxN+MaxM], front_y, back_y;
int max(){
int *front = NULL;
int Max = 1<<31;
if(front_a!=back_a && a[front_a]>Max){
front = &front_a;
Max = a[front_a];
}
if(front_x!=back_x && x[front_x]>Max){
front = &front_x;
Max = x[front_x];
}
if(front_y!=back_y && y[front_y]>Max){
front = &front_y;
Max = y[front_y];
}
++(*front);
return Max;
}
最核心的問題解決了。現在還面臨一個問題:每1秒除剛剛產生的蚯蚓外,其餘長度全部增加q。如果按照題意來模擬,將其餘全部佇列中的元素掃描一遍並加q,單次操作的複雜度便達到了O(N+M),這是顯然吃不消的。
還有更優的辦法嗎?
反過來想:他讓我們把其餘元素加q,那我們不妨把新產生的兩個元素減q,這樣各個元素之間的相對值是保持不變的。但是最終所有元素的值與實際值也肯定存在一個相對值“Plus”,我們只要最後把他加回來就好了。
程式碼如下:
bool flag = false;
int Plus = 0;
int cnt = 0;
for(int m = 1; m<=M; ++m){
now = max()+Plus;
if(m%T==0 && cnt<M/T){
flag ? printf(" ") : flag = true;
printf("%d", now);
++cnt;
}
_x = int(now*P); //left
_y = now-_x; //right
Plus += Q;
x[back_x++] = _x-Plus;
y[back_y++] = _y-Plus;
}
printf("\n");
最主要的兩個問題解決了,其他的估計也就順理成章了吧!下附總程式碼
#include <cstdio>
#include <algorithm>
using namespace std;
const int MaxN = 100000+2;
const int MaxM = 7000000+2;
int N, M, Q, U, V, T;
int _x, _y, Plus;
int cnt, now;
double P;
bool flag;
int a[MaxN], front_a, back_a;
int x[MaxN+MaxM], front_x, back_x;
int y[MaxN+MaxM], front_y, back_y;
inline bool cmp(int a, int b){
return a>b;
}
int max(){
int *front = NULL;
int Max = 1<<31;
if(front_a!=back_a && a[front_a]>Max){
front = &front_a;
Max = a[front_a];
}
if(front_x!=back_x && x[front_x]>Max){
front = &front_x;
Max = x[front_x];
}
if(front_y!=back_y && y[front_y]>Max){
front = &front_y;
Max = y[front_y];
}
++(*front);
return Max;
}
int main() {
freopen("earthworm.in", "r", stdin); //freopen("earthworm.out", "w", stdout);
scanf("%d %d %d %d %d %d", &N, &M, &Q, &U, &V, &T);
P = U/double(V);
for(int i = 0; i<N; ++i) scanf("%d", &a[back_a++]);
sort(a, a+N, cmp);
for(int m = 1; m<=M; ++m){
now = max()+Plus;
if(m%T==0 && cnt<M/T){
flag ? printf(" ") : flag = true;
printf("%d", now);
++cnt;
}
_x = int(now*P);
_y = now-_x;
Plus += Q;
x[back_x++] = _x-Plus;
y[back_y++] = _y-Plus;
}
printf("\n");
flag = false;
cnt = 0;
for(int m = 1; cnt<(N+M)/T; ++m){
now = max()+Plus;
if(m%T==0){
flag ? printf(" ") : flag = true;
printf("%d", now);
++cnt;
}
}
printf("\n");
fclose(stdin); fclose(stdout); return 0;
}
相關文章
- 蚯蚓
- 洛谷P1563 [NOIP2016 提高組] 玩具謎題
- 洛谷 P1850 [NOIP2016 提高組] 換教室 做題記錄
- 洛谷題單指南-數學基礎問題-P2822 [NOIP2016 提高組] 組合數問題
- P2831 [NOIP2016 提高組] 憤怒的小鳥
- 二、RHCSA試題解析
- 測試面試問題(二)面試
- NOIP2016
- 機器學習筆試題精選(二)機器學習筆試
- 試題 演算法提高 質數2(C語言)演算法C語言
- 試題集—— 演算法提高 學霸的迷宮演算法
- CSP-S/NOIP提高組 真題題解總結
- 軟體測試面試問題_介面測試(二)面試
- 提高GUI自動化測試穩定性解決方案GUI
- 題解--NOIP提高組2004 合併果子
- 前端面試&筆試&錯題指南(二)前端面試筆試
- C++二叉樹筆試題C++二叉樹筆試
- 四道筆試題詳解筆試
- 試題 演算法提高 小寫轉換為大寫 C++演算法C++
- Josephus問題解決方法二
- 二分答案解題技巧
- JavaWeb測試選擇題帶答案解析(二)JavaWeb
- 設計模式面試與筆試題剖析(二)設計模式面試筆試
- 如何提高介面測試的效率
- 測試人員如何提高API功能測試效率?API
- CCF-NOIP-2018 提高組(複賽) 模擬試題(一)
- CCF-NOIP-2018 提高組(複賽) 模擬試題(三)
- 【筆試題解】http-client-module筆試HTTPclient
- 藍橋杯歷年(省賽)試題彙總及試題詳解
- 修改 support 包 TabLayout,實現新浪微博/即刻 APP 蚯蚓導航效果TabLayoutAPP
- 想提高團隊技術,來試試這個套路!
- 【程式設計測試題】素數對、不要二、求和程式設計
- 陶哲軒實分析 3.3 節習題試解
- 字串類習題、面試題詳解(第二篇)字串面試題
- 洛谷題單指南-線性表-P2058 [NOIP2016 普及組] 海港
- 二分法解題思路
- 像程式設計師一樣思考——提高解決問題的能力程式設計師
- 晨讀感悟 | 提高快速解決問題的能力的1個方法