2025.2.5 鲜花
如何优雅的用反悔贪心思路做出模拟费用流(HZTG3003. 皮胚 题解)
みむかゥわナイストライ
UN◯♡ おやぁ? 手札多過ぎクッソワロタw 次のターンで私が勝ちまちゅね♡ そのザコさの秘訣を教えてちょ♡ う・じ・む・し・ちゃ・ん♡ ねェカッコわるく負けちゃァだぁ〜めっ ほら が〜んばれっ♡が〜んばれっ♡ ホンキ出したら勝てるんでしょ(笑) は・や・く・み・せ・て?♡(煽り) (十枚)︙ズ干Cャ 丄丶"㐴団" /\ 吖︙㾎ヅKャ 1了‹‹ 10 ‹ノ1/\ 此奴はイわずと知れた い・く・じ・な・し♡ ジャケラ Ha Ha Ha ぴえん 越えて だっさぁ♡ Ow Ow Ow ぱおん 越えて ざっまぁ♡ Beh Beh Beh You're an idiot ☻ されど その場しのぎは→ Shhh ジャケラ Ha Ha Ha ぴえん 越えて だっさぁ♡ Ow Ow Ow ぱおん 越えて ざっまぁ♡ Beh Beh Beh GAME SET ハイ みむかゥわナイストライ♡ ざぁーこ♡ざぁーこ♡たぁ♡ ざぁーこ♡ざぁーこ♡わぁ♡ ざぁーこ♡ざぁーこ♡けぇ♡ 酸性雨に埋まっちゃえ♡Cla-Cla-Clap ざぁーこ♡ざぁーこ♡ばぁー♡ ざぁーこ♡ざぁーこ♡か♡ ざぁーこ♡ざぁーこ♡ =Dynamite= 33-4 なんで手札出さねえの? ひょっとして ひよってんの? まじくっそだせえな あ・く・し・ろ・よ(・д・)チッ ざこざこざこざこざこざこざこざこ ざこざこざこざこざこざこざこざこ ざこざこざこざこざこざこざこざこ ね 早く出そ? もし私に勝ったら 此奴の言うことを なんでも聞いたげるよ♡ まあ 勝てないけどっ♡(笑) 噛ませ犬に抜擢 よわよわ此奴ァわ♡ 所詮先の時代の は・い・ぼ・く・しゃ ♡ ジャケェラ Ha Ha Ha ぴえん 越えて だっさぁ♡ Ow Ow Ow ぱおん 越えて ざっまぁ♡ Beh Beh Beh You're an idiot ☻ されど その場しのぎ は→ Shhh ジャケラ Ha Ha Ha ぴえん 越えて だっさぁ♡ Ow Ow Ow ぱおん 越えて ざっまぁ♡ Beh Beh Beh GAME SET ハイ みむかゥわナイストライ♡ ざぁーこ♡ざぁーこ♡たぁ♡ ざぁーこ♡ざぁーこ♡わぁ♡ ざぁーこ♡ざぁーこ♡けぇ♡ 酸性雨に埋まっちゃえ♡Cla-Cla-Clap ざぁーこ♡ざぁーこ♡ばぁー♡ ざぁーこ♡ざぁーこ♡かぁ♡ ざぁーこ♡ざぁーこ♡ たわいない最終回 対ヨロ ざぁーこ♡ざぁーこ♡ ざぁーこ♡ざぁーこ♡ ざぁーこ♡ざぁーこ♡ =Dynamite= 33-4 負けちゃお?♡負けちゃお?♡ね? みじめに生き恥さらしちゃお?♡ 出せっ♡出せっ♡出せっ♡出せっ♡ "敗北宣言" ぶちまけろっっ♡ う"わ"あ"あ"あ"あ"あ"あ" あ"あ"あ"あ"ん"ん"(豆腐メンタル)
我不会费用流。
考虑贪心做这道题,首先显然的贪心是每次选最大的没匹配的边,也显然假。
考虑假的原因,发现其事实上可以通过交错路来匹配两个不相关的点,考虑将这样的点对之间连边当做是反悔策略,贡献就是和原来的差。
考虑到每个节点的度最多是
发现关键性质,
因为每次最多多选
现在的复杂度是
注意到我们的交错路只和与交错路连通块相交的那个点有关,所以枚举边并不在复杂度上限。
发现这些放到堆里的边权值都不变,于是直接基排后用队列维护就可以了,复杂度
跳交错路相当于是退流,所以写出来和模拟费用流一模一样啦~
Code
#include <bits/stdc++.h> using namespace std; using llt = long long; using ull = unsigned long long; using llf = long double; #define endl '\n' #ifdef LOCAL FILE *InFile = freopen("in_out/in.in", "r", stdin), *OutFile = freopen("in_out/out.out", "w", stdout); #else FILE *InFile = freopen("pp.in", "r", stdin), *OutFile = freopen("pp.out", "w", stdout); #endif const int LG = 20, N = (1 << LG) + 3; int n, ck, clg, cv[N]; pair<int, int> ce[N * 10], *ft = ce + 1, *bk = ce + 1; struct Gph{ int hd[N], nt[N * 20], to[N * 20], tot = 1; bool wt[N * 20]; void Add(int u, int v, bool w){ wt[++tot] = w, to[tot] = v, nt[tot] = hd[u], hd[u] = tot; } void ADD(int u, int v, int w){ Add(u, v, w), Add(v, u, w); } #define For_to(i, u, v, g) for(int i = g.hd[u], v = g.to[i]; i; i = g.nt[i], v = g.to[i]) } g; vector<int> nd; bool vnd[N]; int clv, to[N], vis[N]; int aaa; int Dfs(int u, bool l){ ++aaa; vis[u] = clv; if(!vnd[u]) return cv[u]; int ma = -0x3f3f3f3f; For_to(i, u, v, g) if(vis[v] != clv && g.wt[i] != l) ma = max(ma, Dfs(v, l ^ 1)); return ma; } int To(int u, bool l){ vis[u] = clv; if(!vnd[u]) return cv[u]; int ma = -0x3f3f3f3f; For_to(i, u, v, g) if(vis[v] != clv && g.wt[i] != l){ int t = To(v, l ^ 1); if(ma < t) ma = t, to[u] = v; } return ma; } void Rev(int u, bool l){ if(!vnd[u]){ nd.emplace_back(u), vnd[u] = 1; return ; } For_to(i, u, v, g) if(v == to[u]) Rev(v, l ^ 1), g.wt[i] ^= 1, g.wt[i ^ 1] ^= 1; }; int main(){ ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr); cin >> clg >> ck; n = 1 << clg; for(int i = 0; i < n; ++i) cin >> cv[i]; { static pair<int, int> tp[N * 10]; int ct = 0; for(int u = 0; u < n; ++u) for(int j = 0; j < clg; ++j) if(u & (1 << j)){ int v = u ^ (1 << j); g.ADD(u, v, 0); tp[++ct] = {u, v}; } const int V = 2e6 + 3; static int tmp[V]; for(int i = 1; i <= ct; ++i){ auto &[u, v] = tp[i]; ++tmp[cv[u] + cv[v]]; } for(int i = V - 3; ~i; --i) tmp[i] += tmp[i + 1]; for(int i = ct; i; --i){ auto &[u, v] = tp[i]; ce[tmp[cv[u] + cv[v]]--] = tp[i]; } bk += ct; } int ans = 0; memset(to, -1, sizeof to); for(int ccc = 1; ccc <= ck; ++ccc){ while(ft != bk){ auto [u, v] = *ft; if(vnd[u] || vnd[v]) ++ft; else break; } auto [eu, ev] = *ft; int ema = -1; if(ft != bk) ema = cv[eu] + cv[ev]; int nma = 0, nu = 0, nv = 0; for(auto u : nd){ int tp = Dfs(u, 0); For_to(i, u, v, g) if(!g.wt[i]){ int t = tp + cv[v] * (!vnd[v]); if(t > nma) nma = t, nu = u, nv = v; ++clv; } } if(max(nma, ema) <= 0) break; if(nma > ema){ ans += nma; To(nu, 0), ++clv; Rev(nu, 0), ++clv; For_to(i, nu, v, g) if(v == nv) g.wt[i] = g.wt[i ^ 1] = 1; if(!vnd[nu]) nd.emplace_back(nu), vnd[nu] = 1; if(!vnd[nv]) nd.emplace_back(nv), vnd[nv] = 1; }else{ ans += ema; ++ft; For_to(i, eu, v, g) if(v == ev) g.wt[i] = g.wt[i ^ 1] = 1; nd.emplace_back(eu), nd.emplace_back(ev), vnd[eu] = vnd[ev] = 1; } } cout << ans << endl; }
P
本文来自博客园,作者:5k_sync_closer,转载请注明原文链接:https://www.cnblogs.com/xrlong/p/18700110
版权声明:本作品采用 「署名-非商业性使用-相同方式共享 4.0 国际」许可协议(CC BY-NC-SA 4.0) 进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了