1455G Forbidden Value(資料結構優化dp+啟發式合併)
1455G Forbidden Value(資料結構優化dp+啟發式合併)
Educational Codeforces Round 99 (Rated for Div. 2)
G. Forbidden Value
題意:給一個初始值為 0 0 0 的變數 x x x 以及一段只包含 s e t 、 i f 、 e n d set、if、end set、if、end 的簡易程式碼段,程式碼 “ s e t y v set~y~v set y v” 表示將 x x x 賦值為 y y y,或者花費 v v v 的代價不執行該語句,程式碼塊 i f y . . . e n d if~y~...~end if y ... end 為條件語句塊,當 x x x 的值等於 y y y 時才會進入該程式碼塊,程式碼塊可以巢狀。在程式的執行過程當中一旦 x x x 的值變成了 s s s 就會立馬崩潰,現在問至少要花費多少的代價才能讓程式正常跑完。
範圍: 1 ≤ n ≤ 2 e 5 , 1 ≤ s ≤ 2 e 5 , 0 ≤ y ≤ 2 e 5 , 1 ≤ v ≤ 1 e 9 1 \le n \le 2e5, 1 \le s \le 2e5, 0 \le y \le 2e5, 1 \le v \le 1e9 1≤n≤2e5,1≤s≤2e5,0≤y≤2e5,1≤v≤1e9。
分析: 可以先考慮基本的 d p dp dp, d p i j dp_{ij} dpij 表示執行完第 i i i 條語句後 x x x 的值為 j j j 所需要的最小代價。若程式碼段中只存在 s e t set set 語句的話這個 d p dp dp 很好寫,只需要注意進行離散化。現在考慮 i f . . . e n d if~...~end if ... end 語句塊,可以發現處理語句塊內部只是與本道題本質相同規律減少的子問題,因此我們可以對該問題進行遞迴的求解,假設進入內部 i f . . . e n d if~...~end if ... end 語句塊所需要的代價為 c o s t cost cost,那麼在處理完內部 i n n e r _ d p inner\_dp inner_dp 後與外部 o u t e r _ d p outer\_dp outer_dp 進行合併時 o u t e r _ d p i j = m i n ( o u t e r _ d p i j , c o s t + i n n e r _ d p i j ) outer\_dp_{ij} = min(outer\_dp_{ij}, cost + inner\_dp_{ij}) outer_dpij=min(outer_dpij,cost+inner_dpij) 即可,總體的時間複雜度為 O ( n 2 ) O(n^2) O(n2),考慮進行優化。
兩個大方向可以進行優化:
① 對於一條 s e t y v set~y~v set y v 語句,除了 j = = y j == y j==y 其餘所有的 j j j 為了保持原來的值都需要增加 v v v 的代價,而 j = = y j == y j==y 在這條語句過後一定會保持 j = = y j == y j==y,因此在這條語句之前 j j j 可以是任何值,所以我們應當取其中代價最小的。注意到每次只有一個 j j j 的變化不同,其他 j j j 的變化都相同,因此我們可以設定一個偏移量 o f f s e t offset offset 儲存所有 j j j 的變化量,只修改一個 j = = y j == y j==y 的值,這裡我們需要一個快速單點修改以及求全域性最小值的功能,STL 中的容器 S e t Set Set 可以滿足,時間複雜度從 O ( n ) O(n) O(n) 降低為 O ( l o g n ) O(logn) O(logn)。
② 上述的樸素 d p dp dp 合併方式的時間複雜度為 O ( n 2 ) O(n^2) O(n2),這裡可以使用啟發式合併的方式,每次合併的時候都是 s i z e size size 較小的 d p dp dp 合併至 s i z e size size 較大的 d p dp dp,時間複雜度從 O ( n 2 ) O(n^2) O(n2) 降低為 O ( n l o g n ) O(nlogn) O(nlogn),不過這裡我們需要維護 S e t Set Set 等資料結構,時間複雜度為 O ( n l o g n l o g n ) O(nlognlogn) O(nlognlogn)。
通過上述的優化,資料結構 s e t set set 與 m a p map map 優化的 d p dp dp 配合啟發式合併,將時間複雜度減小到 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n),足以通過本題。
Code:
#include <bits/stdc++.h>
#define int long long
#define double long double
using namespace std;
inline int read()
{
int s = 0, w = 1;
char ch = getchar();
while (ch < '0' || ch > '9')
{
if (ch == '-')
w = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9')
s = s * 10 + ch - '0', ch = getchar();
return s * w;
}
const int MAXN = 2e5 + 10;
const int INF = 1e18;
const int MOD = 1e9 + 7;
const double eps = 1e-9;
const double PI = acos(-1.0);
int n, s;
struct Node
{
int offset;
map<int, int> mp;
multiset<int> ms;
};
vector<Node> vec;
void update(Node &node, int y, int v)
{
if (node.mp.count(y))
{
node.ms.erase(node.ms.find(node.mp[y]));
}
node.mp[y] = v;
node.ms.insert(v);
}
signed main()
{
n = read(), s = read();
int skip = 0;
vec.push_back({});
vec.back().offset = 0;
vec.back().mp[0] = 0;
vec.back().ms.insert(0);
for (int i = 0; i < n; i++)
{
string op;
int y, v;
cin >> op;
if (op[0] == 's')
{
y = read(), v = read();
if (skip) continue;
int minV = *vec.back().ms.begin() - v;
vec.back().offset += v;
if (y != s)
{
update(vec.back(), y, minV);
}
}
else if (op[0] == 'i')
{
y = read();
if (!skip && vec.back().mp.count(y))
{
int val = vec.back().mp[y] + vec.back().offset;
vec.back().ms.erase(vec.back().ms.find(vec.back().mp[y]));
vec.back().mp.erase(y);
vec.push_back({});
vec.back().offset = 0;
update(vec.back(), y, val);
}
else
{
skip++;
}
}
else
{
if (skip) skip--;
else
{
if (vec[vec.size() - 1].mp.size() > vec[vec.size() - 2].mp.size())
{
swap(vec[vec.size() - 1], vec[vec.size() - 2]);
}
auto &outer = vec[vec.size() - 2];
for (auto x : vec.back().mp)
{
if (!outer.mp.count(x.first) || (outer.offset + outer.mp[x.first] > vec.back().offset + x.second))
{
int val = vec.back().offset + x.second - outer.offset;
update(outer, x.first, val);
}
}
vec.pop_back();
}
}
}
cout << vec.back().offset + *vec.back().ms.begin() << endl;
return 0;
}
【END】感謝觀看
相關文章
- 樹上啟發式合併總結
- 啟發式合併
- 高併發,大資料量系統的資料結構優化思路大資料資料結構優化
- 資料結構--線段樹合併資料結構
- 樹上啟發式合併
- 微服務 - Redis快取 · 資料結構 · 持久化 · 分散式 · 高併發微服務Redis快取資料結構持久化分散式
- mysql資料庫多表同結構合併資料MySql資料庫
- HDU7458-啟發式合併最佳化DP
- Spark效能優化:優化資料結構Spark優化資料結構
- 資料庫結構的優化資料庫優化
- java併發資料結構之CopyOnWriteArrayListJava資料結構
- Java中結構化併發Java
- 結構化資料、半結構化資料和非結構化資料
- java八股 併發+資料結構Java資料結構
- 大資料量高併發的資料庫優化大資料資料庫優化
- [分散式][高併發]熱點快取的架構優化分散式快取架構優化
- 實時資料併發寫入 Redis 優化Redis優化
- MySQL資料庫效能優化之表結構優化(轉)MySql資料庫優化
- dsu on tree (樹上啟發式合併) 詳解
- 併發應用中不可變資料結構資料結構
- 淺談演算法和資料結構(3):合併排序演算法資料結構排序
- 【資料結構】歸併排序!!!資料結構排序
- 【資料結構】歸併排序資料結構排序
- 前端效能優化 --- 資源合併與壓縮前端優化
- 資料結構 中綴表示式轉化資料結構
- 資料結構:快速排序程式碼(已優化)資料結構排序優化
- PostgreSQLraster(柵格資料)st_value優化舉例SQLAST優化
- 實戰資料結構(3)_兩個單連結串列間的合併操作資料結構
- Flowmatic:Go語言中結構化併發庫Go
- 結構化資料與非結構化資料的差異
- 網際網路級別大變革:本地優先軟體!在本地擁有自己的資料,使用CRDT資料結構實現分散式資料合併!資料結構分散式
- .NET併發程式設計-資料結構不可變性程式設計資料結構
- 效能調優-Mysql索引資料結構詳解與索引優化MySql索引資料結構優化
- 【dp+離散化+線段樹優化】Paint優化AI
- 段合併優化及注意事項優化
- 一次UnionAll的合併優化優化
- 資料結構 歸併排序 C++資料結構排序C++
- 高併發優化方向優化