2024.2.20 鲜花

ABC221G 和 P5163 题解

命に嫌われている。
「死にたいなんて言うなよ。」
「諦めないで生きろよ。」
そんな歌が正しいなんて馬鹿げてるよな。
実際自分は死んでもよくて
周りが死んだら悲しくて
「それが嫌だから」っていうエゴなんです。
他人が生きてもどうでもよくて
誰かを嫌うこともファッションで
それでも「平和に生きよう」なんて
素敵なことでしょう。
画面の先では誰かが死んで
それを嘆いて誰かが歌って
それに感化された少年がナイフを持って走った。
僕らは命に嫌われている。
価値観もエゴも押し付けて
いつも誰かを殺したい歌を
簡単に電波で流した。
僕らは命に嫌われている。
軽々しく死にたいだとか
軽々しく命を見てる 僕らは命に嫌われている。
お金がないので今日も 一日中惰眠を謳歌する。
生きる意味なんて見出せず、
無駄を自覚して息をする。
「寂しい」なんて言葉でこの傷が表せていいものか
そんな意地ばかり抱え今日も一人ベッドに眠る
少年だった僕たちはいつか青年に変わってく。
年老いていつか枯れ葉のように
誰にも知られず朽ちていく。
不死身の身体を手に入れて、
一生死なずに生きていく。
そんなSFを妄想してる
自分が死んでもどうでもよくて
それでも周りに生きて欲しくて
矛盾を抱えて生きてくなんて怒られてしまう。
「正しいものは正しくいなさい。」
「死にたくないなら生きていなさい。」
悲しくなるならそれでもいいなら
ずっと一人で笑えよ。
僕らは命に嫌われている。
幸福の意味すらわからず
生まれた環境ばかり憎んで
簡単に過去ばかり呪う。
僕らは命に嫌われている。
さよならばかりが好きすぎて
本当の別れなど知らない 僕らは命に嫌われている。
幸福も別れも愛情も友情も
滑稽な夢の戯れで全部カネで買える代物。
明日死んでしまうかもしれない。
すべて無駄になるかもしれない。
朝も 夜も 春も 秋も
変わらず誰かがどこかで死ぬ。
夢も明日も何もいらない。
君が生きていたならそれでいい。
そうだ。本当はそういうことが歌いたい。
命に嫌われている。
結局いつかは死んでいく。
君だって僕だっていつかは枯れ葉のように朽ちてく。
それでも僕らは必死に生きて
命を必死に抱えて生きて
殺して、足掻いて、笑って、抱えて
生きて、生きて、生きて、生きて、生きろ。

ABC221G

省流:可以直接看最下面 wang54321 的写法,应该是最简洁的。

首先假装大家都会 n2D 的做法,简单说就是考虑分别计算出 X+YXY 的方案(也可以说是转坐标轴),然后就可以得 XY 并推出方案。

经过一些转化问题成功变成了如下经典问题:

n 个物品,每个的重量 wD 求是否可以选出若干个使其重量是 T

使用 bitset 不难给出 O(nTw) 的做法,但在这个题 TnD 并不足够优秀。

考虑能否 nD 解决问题。

容易想到经典结论,先从前往后尽可能多的取,设取到位置 p 和为 S,显然有 S(TD,T],然后考虑背包微调,有结论其在微调的任意时刻一定可以满足 S(TD,T+D],证明不太难。

fl,r,w=0/1 表示在 lpr 中微调能否达到 w 的权值,显然 w 的范围只有 2D,每次分讨向左是否扔掉和向右拿上即可转移,设序列为 a,给个方程。

fl1,r,wfl,r,w

fl1,r,wal1fl,r,w

fl,r+1,wfl,r,w

fl,r+1,w+ar+1fl,r,w

其依然是 n2D 的,考虑优化,发现当 r,w 固定时 fl,r,w1l 的一段前缀,于是转而设 gr,w=l 表示最大的 l 满足 fl,r,w=1,若没有就是 0

转移依然分讨左右是否改变,这里由于是最大所以不用考虑向左但不扔的转移,方程:

gr,wgr1,w

gr,wargr1,wwT

gr,w+allwT&l<gr,w

由于第三个转移,我们依然要枚举 l,复杂度没变。

但是我们惊奇的发现,对于 l<gr1,wl,其可以通过 lgr1,wgr,w 转移,于是我们的 l 只用枚举 [gr1,w,gr,w) 的了。

显然将 w 相等的拼起来其最多是 O(n) 的,于是我们成功做到了 nD

主播主播,上面的一堆推导还是太需要操作了,有没有简单无脑还快的做法呢?

还真有,考虑 wang54321 的简单做法。

依然是先尽可能多选,根据结论这时我们只会在值域 (TD,T+D] 上跳,并且我们已经跳到一个点上了。

于是乎我们直接暴力枚举序列中每个数,以此取反其选取情况,就会得到 n 个新状态,每次扩展到没有被跳过的点上再次暴力即可,容易发现一共只有 O(D) 个点,每个点扩展 n 次,复杂度依然是 nD 的。原理其实和上面的很类似。

这里给出第一种做法的代码。

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 复杂度并不正确,容易想到的是先处理左边,在将左边处理剩下的残图加边接着跑,很可惜复杂的依然是错的,考虑若没有强连通分量,则每次最坏依然是 O(n) 的。

这里有一个比较牛的做法,考虑每次先缩点,在将缩了的点放到左边,不属于连通分量的边放到右边。考虑这样我们和上面的区别,我们每次把边分成了两边,避免了不能缩的边在左边继续计算,于是只要我们 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

posted @   5k_sync_closer  阅读(63)  评论(6编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示