2024.2.20 鲜花
ABC221G 和 P5163 题解
命に嫌われている。
「死にたいなんて言うなよ。」 「諦めないで生きろよ。」 そんな歌が正しいなんて馬鹿げてるよな。 実際自分は死んでもよくて 周りが死んだら悲しくて 「それが嫌だから」っていうエゴなんです。 他人が生きてもどうでもよくて 誰かを嫌うこともファッションで それでも「平和に生きよう」なんて 素敵なことでしょう。 画面の先では誰かが死んで それを嘆いて誰かが歌って それに感化された少年がナイフを持って走った。 僕らは命に嫌われている。 価値観もエゴも押し付けて いつも誰かを殺したい歌を 簡単に電波で流した。 僕らは命に嫌われている。 軽々しく死にたいだとか 軽々しく命を見てる 僕らは命に嫌われている。 お金がないので今日も 一日中惰眠を謳歌する。 生きる意味なんて見出せず、 無駄を自覚して息をする。 「寂しい」なんて言葉でこの傷が表せていいものか そんな意地ばかり抱え今日も一人ベッドに眠る 少年だった僕たちはいつか青年に変わってく。 年老いていつか枯れ葉のように 誰にも知られず朽ちていく。 不死身の身体を手に入れて、 一生死なずに生きていく。 そんなSFを妄想してる 自分が死んでもどうでもよくて それでも周りに生きて欲しくて 矛盾を抱えて生きてくなんて怒られてしまう。 「正しいものは正しくいなさい。」 「死にたくないなら生きていなさい。」 悲しくなるならそれでもいいなら ずっと一人で笑えよ。 僕らは命に嫌われている。 幸福の意味すらわからず 生まれた環境ばかり憎んで 簡単に過去ばかり呪う。 僕らは命に嫌われている。 さよならばかりが好きすぎて 本当の別れなど知らない 僕らは命に嫌われている。 幸福も別れも愛情も友情も 滑稽な夢の戯れで全部カネで買える代物。 明日死んでしまうかもしれない。 すべて無駄になるかもしれない。 朝も 夜も 春も 秋も 変わらず誰かがどこかで死ぬ。 夢も明日も何もいらない。 君が生きていたならそれでいい。 そうだ。本当はそういうことが歌いたい。 命に嫌われている。 結局いつかは死んでいく。 君だって僕だっていつかは枯れ葉のように朽ちてく。 それでも僕らは必死に生きて 命を必死に抱えて生きて 殺して、足掻いて、笑って、抱えて 生きて、生きて、生きて、生きて、生きろ。
ABC221G
省流:可以直接看最下面 wang54321 的写法,应该是最简洁的。
首先假装大家都会
经过一些转化问题成功变成了如下经典问题:
有
个物品,每个的重量 求是否可以选出若干个使其重量是 。
使用 bitset
不难给出
考虑能否
容易想到经典结论,先从前往后尽可能多的取,设取到位置
设
其依然是
转移依然分讨左右是否改变,这里由于是最大所以不用考虑向左但不扔的转移,方程:
由于第三个转移,我们依然要枚举
但是我们惊奇的发现,对于
显然将
主播主播,上面的一堆推导还是太需要操作了,有没有简单无脑还快的做法呢?
还真有,考虑 wang54321 的简单做法。
依然是先尽可能多选,根据结论这时我们只会在值域
于是乎我们直接暴力枚举序列中每个数,以此取反其选取情况,就会得到
这里给出第一种做法的代码。
Code
/* Local File in_out/in.in in_out/out.out */ #include <bits/stdc++.h> using namespace std; using llt = long long; using llf = long double; using ull = unsigned long long; #ifndef LOCAL #undef assert #define assert 0 && #define cerr 0 && cerr #endif const int N = 2003, D = 1803; int n, cx, cy, cd[N]; bool cv1[N], cv2[N]; int _f[D * 2], *const f = _f + D, _g[D * 2], *const g = _g + D, chs[N][D * 2]; /* for : r g_w <- f_w g_{w + v_r} <- f_w | w <= 0 g_{w - v_l} <- l | f_w < l < g_w && w >= 0 */ bool Dp(int tw, bool *ans){ int p = 1, s = 0; while(p <= n && s + cd[p] <= tw) s += cd[p++]; memset(_f, 0, sizeof _f), memset(_g, 0, sizeof _g), memset(chs, 0, sizeof chs); g[s - tw] = f[s - tw] = p; for(int r = p; r <= n; ++r){ auto nc = chs[r] + D; auto Upd = [&](int p, int v, int f){ if(g[p] < v) g[p] = v, nc[p] = f; }; for(int w = -D + 3; w <= 0; ++w) Upd(w + cd[r], f[w], -1); for(int w = D - 3; ~w; --w) for(int l = f[w]; l < g[w]; ++l) Upd(w - cd[l], l, l); memcpy(_f, _g, sizeof _f); } if(!g[0]) return 0; for(int i = 1; i < p; ++i) ans[i] = 1; int r = n, v = 0; while(r >= p){ int f = chs[r][v + D]; if(f == 0) --r; else if(f == -1) ans[r] = 1, v -= cd[r], --r; else if(f > 0) ans[f] = 0, v += cd[f]; } return 1; } int main(){ cin >> n >> cx >> cy; int s = 0; for(int i = 1; i <= n; ++i) cin >> cd[i], s -= cd[i]; int b1 = cx + cy - s, b2 = cx - cy - s; if(b1 < 0 || b2 < 0 || b1 % 2 || b2 % 2 || !Dp(b1 / 2, cv1) || !Dp(b2 / 2, cv2)) cout << "No" << endl; else{ cout << "Yes" << endl; for(int i = 1; i <= n; ++i) if(cv1[i] == cv2[i]) cout << (cv1[i] ? 'R' : 'L'); else cout << (cv1[i] ? 'U' : 'D'); } }
P5163
如果是无向边是显的。
考虑有向边和无向边的区别是什么,其实没什么区别,只是我们需要知道每个边归到连通分量的时间。
考虑对于一条边如何确定,可以二分,每次判断加入 mid 之前的边自己是否归于一个连通分量。对于所有边,容易想到整体二分。
考虑 check,如果是暴力 tarjan 复杂度并不正确,容易想到的是先处理左边,在将左边处理剩下的残图加边接着跑,很可惜复杂的依然是错的,考虑若没有强连通分量,则每次最坏依然是
这里有一个比较牛的做法,考虑每次先缩点,在将缩了的点放到左边,不属于连通分量的边放到右边。考虑这样我们和上面的区别,我们每次把边分成了两边,避免了不能缩的边在左边继续计算,于是只要我们 tarjan 只做非孤立点,复杂度就是对的。
每层右边需要重标号,可以用并查集,也可以每次暴力整。
然后就是板子大战了。
Code
/* Local File in_out/in.in in_out/out.out */ #include <bits/stdc++.h> using namespace std; using llt = long long; using llf = long double; using ull = unsigned long long; #ifndef LOCAL #undef assert #define assert 0 && #define cerr 0 && cerr #endif const int N = 2e6 + 3; int n, m, q, cs[N]; struct Gph{ vector<int> to[N]; void Add(int u, int v){ to[u].emplace_back(v); } void ADD(int u, int v){ Add(u, v), Add(v, u); } void Clr(int u){ to[u].clear(); } #define For_to(i, u, v, g) for(int v : g.to[u]) }g; class TAR{ private: int dfn[N], low[N], stk[N], *top = stk, tdn, tco = 1e5, col[N]; bool isk[N]; void Dfs(int u){ dfn[u] = low[u] = ++tdn; isk[*++top = u] = 1; For_to(i, u, v, g){ if(!dfn[v]) Dfs(v), low[u] = min(low[u], low[v]); else if(isk[v]) low[u] = min(low[u], dfn[v]); } if(dfn[u] == low[u]){ ++tco; int v; do{ v = *top--; col[v] = tco, isk[v] = 0; }while(v != u); } } public: void In(int u){ if(!dfn[u]) Dfs(u); assert(top == stk); } int operator()(int u){ return col[u]; } void Clr(int u){ dfn[u] = low[u] = col[u] = 0; } } Tar; struct E{ int u, v, t, tc, uu, vv; } ce[N]; bool Chk(const E &e){ return Tar(e.u) == Tar(e.v); } void Cdq(int l, int r, int ll, int rr){ if(l == r){ for(int i = ll; i <= rr; ++i) ce[i].tc = l; return ; } int mid = l + r >> 1, mmd; vector<int> nd; for(mmd = ll; mmd <= rr; ++mmd){ auto &[u, v, t, tc, uu, vv] = ce[mmd]; if(t > mid) break; else{ g.Add(u, v); nd.emplace_back(u), nd.emplace_back(v); } } --mmd; for(auto k : nd) Tar.In(k); vector<E> tp; int p = ll - 1; for(int i = ll; i <= mmd; ++i){ if(!Chk(ce[i])) tp.emplace_back(ce[i]); else ce[++p] = ce[i]; } mmd = p; for(auto &k : tp) ce[++p] = k; auto Id = [](int &u){ if(Tar(u)) u = Tar(u); }; for(int i = mmd + 1; i <= rr; ++i) Id(ce[i].u), Id(ce[i].v); for(auto k : nd) Tar.Clr(k), g.Clr(k); Cdq(l, mid, ll, mmd), Cdq(mid + 1, r, mmd + 1, rr); } namespace SEG{ const int D = 1e7 + 3, V = 1e9; int sz[D], ls[D], rs[D], tot; llt sm[D]; #define lson ls[t] #define rson rs[t] #define mid (l + r >> 1) void Upd(int t){ sz[t] = sz[lson] + sz[rson]; sm[t] = sm[lson] + sm[rson]; } llt qry(int l, int r, int k, int t){ if(!t) return 0; if(l == r) return 1ll * l * k; else{ if(k <= sz[rson]) return qry(mid + 1, r, k, rson); else return qry(l, mid, k - sz[rson], lson) + sm[rson]; } } void add(int l, int r, int p, int v, int &t){ if(!t) t = ++tot; if(l == r) sz[t] += v, sm[t] += 1ll * l * v; else{ if(p <= mid) add(l, mid, p, v, lson); else add(mid + 1, r, p, v, rson); Upd(t); } } void mrg(int l, int r, int _, int &t){ if(!_ || !t) t += _; else if(l == r){ sz[t] += sz[_], sm[t] += sm[_]; }else{ mrg(l, mid, ls[_], lson); mrg(mid + 1, r, rs[_], rson); Upd(t); } } #undef lson #undef rson #undef mid class Seg{ private: int rt = 0; public: void Add(int a, int v){ add(0, V, a, v, rt); } llt Qry(int k){ return qry(0, V, k, rt); } void Mrg(const Seg &_){ mrg(0, V, _.rt, rt); } }; } using SEG::Seg; Seg seg[N]; class Dsu{ private: int fa[N]; public: int Fa(int u){ return fa[u] ? fa[u] = Fa(fa[u]) : u; } void Uni(int fu, int fv){ // fu -> fv fa[fu] = fv; } } uf; stack<tuple<int, int, int, int>> cq; int main(){ cin >> n >> m >> q; { map<pair<int, int>, int> eid; for(int i = 1; i <= n; ++i) cin >> cs[i]; for(int i = 1; i <= m; ++i){ int u, v; cin >> u >> v; ce[i] = {u, v, 0, 0, u, v}, eid[{u, v}] = i; } for(int i = 1; i <= q; ++i){ int op, a, b; cin >> op >> a >> b; int t = q - i + 1; if(op == 1) ce[eid[{a, b}]].t = t; else{ cq.emplace(t, op - 1, a, b); if(op == 2) cs[a] += b; } } for(int i = 1; i <= n; ++i) seg[i].Add(cs[i], 1); } sort(ce + 1, ce + m + 1, [](const E &a, const E &b){return a.t < b.t;}); Cdq(0, q + 1, 1, m); for(int i = 1; i <= m; ++i) ce[i].u = ce[i].uu, ce[i].v = ce[i].vv; auto ne = ce + 1; stack<llt> aas; for(int t = 0; t <= q; ++t){ while(ne->tc == t){ int fu = uf.Fa(ne->u), fv = uf.Fa(ne->v); if(fu != fv) uf.Uni(fu, fv), seg[fv].Mrg(seg[fu]); ++ne; } while(!cq.empty() && get<0>(cq.top()) == t){ auto [t, op, a, b] = cq.top(); cq.pop(); int f = uf.Fa(a); if(op == 1) seg[f].Add(cs[a], -1), seg[f].Add(cs[a] -= b, 1); else aas.emplace(seg[f].Qry(b)); } } while(!aas.empty()) cout << aas.top() << endl, aas.pop(); }
P
本文来自博客园,作者:5k_sync_closer,转载请注明原文链接:https://www.cnblogs.com/xrlong/p/18725242
版权声明:本作品采用 「署名-非商业性使用-相同方式共享 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:你的「微服务管家」又秀新绝活了