The 2021 CCPC Guilin Onsite (Grand Prix of EDG) K. Tax
阿新 • • 發佈:2021-11-17
場上隊友想到正解了,但沒機時了,由於我們打星直接不寫這道題了
賽後1A emmm 如果沒打星 過了這題就金了
能過
題意
\(n\)個點和\(m\)條無向邊,點依次從1到n編號。每條邊有一個顏色,如果這是第\(k\)次經過顏色為\(c\)的邊,那麼需要\(k\times w_c\)的代價。
對於\(k=2,3,4,...,n\),回答從\(1\)到\(k\)經過邊數最少的情況下最小代價是多少。
保證沒有重邊並且1號點可以到達其它所有點。
\(2\le n\le 50,n-1\le m \le \frac{n(n-1)}{2}\)
Sol
資料很小考慮亂搞
不考慮優化的話 直接DFS更新答案 複雜度為\(n!\)(完全圖)
預處理出1號點到其它點的最短路(分層)後限制步數、方向+最優性剪枝
考慮此時的最壞情況:
如果把圖根據從1到該點的距離分層,假設層與層之間邊數拉滿,每層點數為\(x\)時每走一層都有\(x\)種選擇,共有\((n-1)/x\)層,複雜度\(O(x^{\frac{n-1}{x}})\)
這玩意非負,直接取對數得\(\frac{n-1}{x}\times\ln(x)\), 再求導得\(-\frac{n-1}{x^2}\ln(x)+\frac{n-1}{x^2}=\frac{n-1}{x^2}(1-\ln(x))\)
\(x=e\)的時候導數為0 取得最大值
由於\(x\)是整數,把2和3分別帶進去得\(2^{\frac{49}{2}}\)能過,\(3^{\frac{49}{3}}\)
由均值不等式知總點數不變的情況下,每層的點數相同的時候複雜度最大
因此最終複雜度O(能過)
但是搜50次肯定寄了
分完層以後按層數跑 不用最優性剪枝了 往下跑就行了 跑到哪個點就更新一下該點的答案
這樣跑滿是上面算出來的複雜度
// Problem: K. Tax // Contest: Codeforces - The 2021 CCPC Guilin Onsite (Grand Prix of EDG) // URL: https://codeforces.com/gym/103409/problem/K // Memory Limit: 512 MB // Time Limit: 1500 ms // // Powered by CP Editor (https://cpeditor.org) #include<bits/stdc++.h> using namespace std; const int maxn = 57, maxm = 10007; #define ll long long int n, m, k, tot; struct edge { int v, c, nxt; }e[maxm]; ll w[maxm], cnt[maxm], ans[maxn]; int d[maxn], head[maxn], eid; int rd() { int s = 0, f = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar();} while (c >= '0' && c <= '9') {s = s * 10 + c - '0'; c = getchar();} return s * f; } void init() { memset(head, -1, sizeof(head)); memset(d, -1, sizeof(d)); memset(ans, 0x3f, sizeof(ans)); eid = 0; } void insert(int u, int v, int c) { e[eid].v = v; e[eid].c = c; e[eid].nxt = head[u]; head[u] = eid++; } void bfs() { queue<int> q; q.push(1); d[1] = 0; while (!q.empty()) { int u = q.front(); //printf("u == %d d[u] == %d\n", u, d[u]); q.pop(); for (int i = head[u]; ~i; i = e[i].nxt) { int v = e[i].v; if (d[v] == -1) { d[v] = d[u] + 1; q.push(v); } } } } void dfs(int u, ll dis) { for (int i = head[u]; ~i; i = e[i].nxt) { int v = e[i].v; if (d[v] == d[u] + 1) { cnt[e[i].c]++; ans[v] = min(ans[v], dis + w[e[i].c] * cnt[e[i].c]); dfs(v, dis + w[e[i].c] * cnt[e[i].c]); cnt[e[i].c]--; } } } int main() { n = rd(); m = rd(); init(); for (int i = 1; i <= m; i++) { w[i] = rd(); } for (int i = 1, u, v, c; i <= m; i++) { u = rd(); v = rd(); c = rd(); //printf("u == %d v == %d c == %d\n", u, v, c); insert(u, v, c); insert(v, u, c); } bfs(); dfs(1, 0); for (int i = 2; i <= n; i++) { printf("%lld\n", ans[i]); } return 0; }