題意:\(n\)個點,\(m\)條邊,每個點有權值,每條邊也有權值(按讀入$\times$2處理),對每個點,選定乙個目標點(可以是它自己),使這個點到達目標點的距離加上目標點的權值的和最小。
\(1 <= n, m<=2e5\)
解法:\(dijkstra\) + 超級源點
這個資料範圍不允許我們跑\(floyd\)或者\(n\)次\(dijkstra\),但我們發現,對於每個點,只需求乙個最小值,並且資料範圍其實也告訴我們了只需要跑一次\(dijkstra\),那麼我們該從那個點跑\(dijkstra\)呢?我們發現很難從圖中找到這樣的乙個點,使得所有的點都和它有關。
我們再梳理一下思路,我們需要找到乙個點,以ta為起點跑一遍單源最短路,並且我們要使得所有的點都和它有關。
我們發現這個點在圖中無法找到,所以我們選擇建立乙個超級源點,讓它想所有的點建一條長度為點的權值的邊,然後從它開始跑一遍\(dijkstra\)。仔細思考一番,我們發現這個演算法的正確性是對的,時間複雜度\(o(nlogn)\)
#include #include #include #include using namespace std;
#define maxn 200100
#define pr pair#define mp make_pair
#define ll long long
int fir[maxn], nxt[maxn * 3], vv[maxn * 3];
ll edg[maxn * 3];
int tot = 0, n, m;
void add(int u, int v, ll w)
ll dis[maxn], vis[maxn], val[maxn];
priority_queue, greater>q;
ll dijkstra(int x)
memset(vis, 0, sizeof(vis));
dis[x] = 0;
q.push(mp(dis[x], x));
while(!q.empty())
}} ll ans = 1e9; ans *= 1e9;
for(int i = 1; i <= n; i++) printf("%d ", dis[i]);
return ans;
}int main()
for(int i = 1; i <= n; i++) scanf("%lld", &val[i]);
for(int i = 1; i <= n; i++) add(n + 1, i, val[i]);
dijkstra(n + 1);
return 0;
}
這是一道做法很簡單的實數二分,但要注意\(l,r\)的取值範圍,\(r\)最大可以取到\(1e6 +1e3\)
同時,要注意\(double\)的精度範圍,\(double\)的有效範圍是\(15\)
\(到16\)位,\(long\,\,double\)的有效範圍是\(18\)到\(19\)位,如果暴範圍了,就很有可能\(l,r\)變成\(0\),然後\(t\)掉。
這是一道很水的列舉刪邊,然後求樹的直徑的題,略過。
11月24日 模擬賽 題解
a 模擬。時間複雜度 o n b 考慮兩個數怎樣排更優。時間複雜度 o nlogn c 乙個數在經過一次操作後貢獻就是 0 了。所以維護最大值的線段樹 每次在上面找未被刪除的 貢獻清零後權值變為 infty 每個數最多刪一次 時間複雜度 o nlogn d 假設初始區間 l r 對應座標軸原點。那麼...
18年11月5日 NOIP模擬賽
對於k 100的情況,貪心 對於100 的資料 可以發現,當前的決策只對後面的開採有影響,且剩餘耐久度與之後的開採收益成正比,如果倒著考慮這個問題,得出i n的星球1點耐久度所能獲得的最大收益,從後往前dp,得出最大值最後乘w就是答案 include includeusing namespace s...
2023年11月15日noip模擬賽
苟.1.謎題 5faq2.選修課 faq3.質數 首先考慮,質數 根號n的情況 我們考慮 根號n以內的質數所組成的最優方案吧。可以搜尋。大概 再考慮根號n以後的質數的方案 好難啊。不會寫啊 gg include include include include include include usin...