訓練賽地址c++
⭐⭐算法
題意:給出一張圖,圖中的節點分爲黑點白點,求出黑點對之間的最短距離並輸出這兩個黑點的編號安全
解析:網絡
那麼假設一個點爲\(a\),另外一個點爲\(b\),如若這兩個點的最近黑點不是一個點,那麼就考慮全部這樣的\(<a,b>\)組合,所組成路徑的最小值即爲答案,即複雜度爲暴力枚舉全部邊\(O(m)\)app
注意:\(pre\)必定要是黑點才行,因此一開始定義全部的\(pre\)都是-1,遇到是-1的點直接跳過他的邊枚舉優化
總結:spa
#include<cstdio> #include<algorithm> #include<vector> #include<cstring> #include<queue> using namespace std; const long long INF = 0x3f3f3f3f3f3f3f3fll; const int maxn = 1e5 + 10; typedef pair <long long, int> P; int n, m; int cnt, sign[maxn];; bool vis[maxn]; vector<P> e[maxn]; vector<int> pre; vector<long long> d; priority_queue<P, vector<P>, greater<P>> q; void dij() { pre.assign(n + 1, -1), d.assign(n + 1, INF); for (int i = 1; i <= n; ++i) if (sign[i]) pre[i] = i, d[i] = 0, q.push(P(d[i], i)); while (!q.empty()) { P t = q.top(); q.pop(); if (d[t.second] < t.first) continue; for (auto& i : e[t.second]) { if (d[i.second] > d[t.second] + i.first) { d[i.second] = d[t.second] + i.first; q.push(P(d[i.second], i.second)); pre[i.second] = pre[t.second]; } } } } void add(int u, int v, int c) { e[u].push_back(P(c, v)); e[v].push_back(P(c, u)); } int main() { int a, b, c; scanf("%d%d", &n, &m); for (int i = 1; i <= n; ++i) scanf("%d", &sign[i]); while (m--) { scanf("%d%d%d", &a, &b, &c); add(a, b, c); } dij(); long long ret = 0x3f3f3f3f3f3f3f3fll; for (int i = 1; i <= n; ++i) { if (pre[i] == -1) continue; for (auto& j : e[i]) if (~pre[j.second] && pre[i] != pre[j.second] && d[i] + d[j.second] + j.first < ret) ret = d[i] + d[j.second] + j.first, a = pre[i], b = pre[j.second]; } if (ret >= 0x3f3f3f3f3f3f3f3fll) printf("No luck at all"); else printf("%lld\n%d %d", ret, a, b); }
⭐⭐.net
題意:
你有\(n\)個任務須要完成,任務按照時間順序交付到你的手上,你在任意時刻能夠花費\(d\)完成以前全部未完成的任務,可是當每個任務被延遲完成一個單位時間會花費\(c\),請問完成這些任務最少花費多少code
解析:隊列
這樣的話求和部分就能夠用前綴和進行\(O(1)\)獲取了
注意:
#include<cstdio> #include<string> #include<algorithm> #define MEM(X,Y) memset(X,Y,sizeof(X)) typedef long long LL; using namespace std; /*===========================================*/ LL dp[1005], sum[1005]; LL dat[1005]; int main(void) { int n, d, c; scanf("%d%d%d", &n, &d, &c); for (int i = 1; i <= n; ++i) { scanf("%lld", &dat[i]); sum[i] = sum[i - 1] + dat[i]; } MEM(dp, INF); dp[0] = 0; for (int i = 1; i <= n; ++i) for (int j = 0; j < i; ++j) dp[i] = min(dp[i], dp[j] + c * ((1LL * i - j) * dat[i] - sum[i] + sum[j]) + d); printf("%lld", dp[n]); }
⭐⭐⭐⭐
題意:
給\(n\)個整數,定義一個數是有序的當且僅當它左邊的數都小於等於它,它右邊的數都大於等於它,排列這\(n\)個整數能組成多少個序列使得全部數都是無序的(答案模取\(10^9+9\))
解析:
\(c\)爲區間內每一個數對應的個數,去除選擇前後性帶來的影響
很明顯能夠發現這個式子能夠進行遞推記錄即
總結:
注意:
#include<bits/stdc++.h> using namespace std; typedef long long LL; const int maxn = 5e3 + 3, mod = 1e9 + 9; LL inv[maxn], permu[maxn][maxn]; LL dat[maxn]; LL dp[maxn]; map<int, int> m; int main() { int n; scanf("%d", &n); inv[1] = 1; for (int i = 2; i <= n; ++i) inv[i] = (mod - mod / i) * inv[mod % i] % mod; for (int i = 1; i <= n; ++i) scanf("%lld", &dat[i]); sort(dat + 1, dat + n + 1); for (int i = 1; i <= n; ++i) { m.clear(); permu[i][i - 1] = 1; for (int j = i; j <= n; ++j) permu[i][j] = permu[i][j - 1] * (j - i + 1) % mod * inv[++m[dat[j]]] % mod; } permu[n + 1][n] = 1; dp[0] = 1; for (int i = 1; i <= n; ++i) { for (int j = 1; j <= i; ++j) dp[i] = (dp[i] + dp[j - 1] * permu[j + 1][i] % mod) % mod; dp[i] = ((permu[1][i] - dp[i]) % mod + mod) % mod; } printf("%lld", dp[n]); }
⭐⭐⭐⭐
題目連接
題意:
有\(n\)個城市\(m\)條道路,道路是雙向的,其中有\(s\)個城市是安全點,每一個城市中都有\(p[i]\)居民,每一個安全點可容納的居民爲\(C[i]\),請問全部城市的居民都到達安全點的最小時間是多少,保證有解
解析:
可是這道題目中輸出流量的城市和最終最大流沒有直接關係,所以能夠將全部流向一樣安全點的城市彙總成一個狀態\(st\),這樣的話點數從\(10^5\)下降到\(2^{10}=1024\)
3. 同時須要進行將城市與狀態相匹配的判斷,這樣就得預先對每一個安全點跑一遍\(dijkstra\),記錄每一個安全點到每一個城市的最小距離,對於每一個城市\(i\),檢測它到每一個安全點的最小距離是否小於當前檢測的\(time\),能夠則將\(i\)歸於狀態\(st\),\(st\)中增長對應的人口數量
4. 爲了下降複雜度,還能夠在二分的範圍上進行優化。能夠將\(dijkstra\)出現的全部可能時間進行記錄後,離散化處理。不一樣時間的種類數最大爲\(10^6\),這樣二分的時間複雜度就從\(\log_210^9\approx50\)下降到\(\log_210^6\approx20\)
注意:
總結:
#include<bits/stdc++.h> #define INF 0x3f3f3f3f #define FRE freopen("abc.in", "r", stdin) #define MEM(X,Y) memset(X,Y,sizeof(X)) typedef long long LL; using namespace std; /*===========================================*/ typedef long long LL; typedef pair<LL, int> P; LL sum; int people[100005]; P saf[15]; LL d[15][100005]; LL st[1050]; vector<pair<LL, int>> e[100005]; priority_queue<P, vector<P>, greater<P> > q; void dij(int x) { int id = saf[x].second; MEM(d[x], INF); d[x][id] = 0; q.push(P(0, id)); while (!q.empty()) { P p = q.top(); q.pop(); int v = p.second; if (d[x][v] < p.first) continue; for (auto& i : e[v]) { if (d[x][i.second] > d[x][v] + i.first) { d[x][i.second] = d[x][v] + i.first; q.push(P(d[x][i.second], i.second)); } } } } //使用非vector鏈式前向星 class MAXFLOW { public: static const int MAXN = 100005; struct Edge { int v, next; LL flow; } e[MAXN * 50]; int head[MAXN], edge_num, layer[MAXN], start, end; void reload() { edge_num = 0; memset(head, -1, sizeof(head)); memset(st, 0, sizeof(st)); } void addedge(int u, int v, LL w) { e[edge_num].v = v; e[edge_num].flow = w; e[edge_num].next = head[u]; head[u] = edge_num++; e[edge_num].v = u; e[edge_num].flow = 0; e[edge_num].next = head[v]; head[v] = edge_num++; } bool bfs() { queue<int> Q; Q.push(start); memset(layer, 0, sizeof(layer)); layer[start] = 1; while (Q.size()) { int u = Q.front(); Q.pop(); if (u == end) return true; for (int j = head[u]; j != -1; j = e[j].next) { int v = e[j].v; if (layer[v] == false && e[j].flow) { layer[v] = layer[u] + 1; Q.push(v); } } } return false; } LL dfs(int u, LL MaxFlow, int End) { if (u == End) return MaxFlow; LL uflow = 0; for (int j = head[u]; j != -1; j = e[j].next) { int v = e[j].v; if (layer[v] - 1 == layer[u] && e[j].flow) { LL flow = min(MaxFlow - uflow, e[j].flow); flow = dfs(v, flow, End); e[j].flow -= flow; e[j ^ 1].flow += flow; uflow += flow; if (uflow == MaxFlow) break; } } if (uflow == 0) layer[u] = 0; return uflow; } LL dinic() { LL MaxFlow = 0; while (bfs()) MaxFlow += dfs(start, 0x3f3f3f3f3f3f3f3f, end); return MaxFlow; } }sol; int n, m, s; vector<LL> tim; bool check(LL time) { sol.reload(); sol.start = 0; for (int i = 1; i <= n; ++i) { int t = 0; for (int j = 1; j <= s; ++j) if (d[j][i] <= time) t |= 1 << (j - 1); st[t] += people[i]; } int mx = 1 << s; for (int i = 1; i < mx; ++i) { sol.addedge(sol.start, i, st[i]); if (!st[i]) continue; for (int j = 1; j <= s; ++j) if (i & (1 << (j - 1))) sol.addedge(i, mx + j, INF); } sol.end = mx + s + 1; for (int i = 1; i <= s; ++i) sol.addedge(i + mx, sol.end, saf[i].first); return sol.dinic() == sum; } int main(void) { int a, b; LL c; scanf("%d%d%d", &n, &m, &s); for (int i = 1; i <= n; ++i) scanf("%d", &people[i]), sum += people[i]; while (m--) { scanf("%d%d%lld", &a, &b, &c); e[a].push_back(P(c, b)); e[b].push_back(P(c, a)); } for (int i = 1; i <= s; ++i) { scanf("%d%lld", &a, &c); saf[i] = P(c, a); dij(i); for (int j = 1; j <= n; ++j) tim.push_back(d[i][j]); } sort(tim.begin(), tim.end()); tim.erase(unique(tim.begin(), tim.end()), tim.end()); int l = 0, r = tim.size() - 1; while (l < r) { int m = l + (r - l) / 2; if (check(tim[m])) r = m; else l = m + 1; } printf("%lld", tim[r]); }