闲话 22.8.17
闲话
考场上被 T3 ex到了
于是放了 T3
本来以为今天又得干到快吃饭才能讲题
但挺快的 反正我没到三点就讲完了
主要是题水
!我似乎还没放《幻影》
这首歌是《幻影EP》的第一首歌,讲述了美影的心理
大概是故事背景 + 第一章
幻影
あなたはだれ?わたしはだれ?
你是谁?我又是谁?
あなたはわたしではないから
因为你我不同
考えていることわからなくて当然
自然没有办法理解对方
わたし、わたしの気持ちなんて
我宁愿不明白自己
わかんなくて良かった
心之所想
その代わりじゃないけど
虽然这并不是我会那样做的替代
その代わりじゃないけど
虽然这并不是我会那样做的替代
本当の言葉で話してって
虽然你随口说了
気軽に言うけどね
让我告诉你真话
誰かと違って
但我不像
そんな賢明に出来てはないからね
其他人那样聪明啊
後悔するってわかっている
虽然我知道
わかってるけど
某天我会后悔
わたし影を作っている
我 创造着幻影
あなたはだれ?わたしはだれ?
你是谁?我又是谁?
本当の心は何処に在るの
真正的心在哪里呢?
あなたはだれ?わたしはだれ?
你是谁?我又是谁?
ぼんやり頭は考えた
脑里的答案依稀不清
Living dark
わたしは幻の影になったの
我变成了幻影
Living dark
わたしは幻の影になったの
我变成了幻影
三番目の影が走り去って行った
第三个影子跑着远去了
わたし、瞳はふたつなんてものじゃ
我只有两只眼睛果然
足りなかった
并不足够
その代わりじゃないけど
虽然这并不是我会那样做的替代
その代わりじゃないけど
虽然这并不是我会那样做的替代
あなたの瞳に夜を描いて
我想把黑夜画进你的瞳孔
眠って欲しかった
让你安眠
揺らめく後ろの髪の輪郭を
我已经记住了你全部的
全部覚えていた
摇曳的后发的轮廓
後悔するってわかっている
虽然我知道某天
わかってるけど
我会后悔
また影を作っている
我还在创造着幻影
話をきいて話をきいて
听我说听我说
本当のわたしはここに居るよ
真正的我就在这里啊
あなたはずっとあなたはずっと
这些日子以来你一直
わたしの影と遊んでいる
都在和我的影子玩耍
Living dark
あなたも幻の影よ影よ
你也是幻影啊幻影啊
Living dark
あなたも幻の影よ 影よ
你也是幻影啊 幻影啊
影よ 影よ
幻影 幻影
わたしのせいでわたしのせいで
都是我的错 都是我的错
本当の言葉が消えてしまうから
导致真正的话语开始消逝
あなたはだれ?わたしはだれ?
你是谁?我又是谁?
幽し影に尋ねていた
我向幽幽的影子询问
あなたにとってあなたにとって
对于你来说 对于你来说
本当の心はどれがよかったの?
我的这些心脏,哪个才是真实的?
幻想のわたしも意外と紙一影
幻想的我和真正的我之间的差别意外地轻如薄纸
Living dark
わたしは幻の影になったの
我变成了幻影
Living dark
わたしは幻の影になったの
我变成了幻影
幻影,也即一个人在其他人面前与自己真实一面不同的表现之总称。
话又说回来了,谁还没有几副面具呢
我正在努力把幻影合起来呢
美影似乎是对于自己的Bad End 所以我该加油
话又说回来了,为什么我到现在才放《幻影》
今天的正经闲话有一部分是早就写完的 所以写得比较快
今日推番(?)是《黄金拼图》!
九条可怜可爱!爱丽丝可爱!
是芳文社所以可以放心去看!
奇妙的Dijkstra
给定一张 \(n\) 个点 \(m\) 条边的带权联通无向图。给定 \(p\) 个关键点,你需要求出每个关键点到最近的其他关键点的距离。
\(n, m \le 10^5, 2\le p \le n\)
考虑求出每个点到关键点的最短距离 \(dis_i\),并保存这个距离对应的关键点 \(key_i\)。
随后枚举边,对于一条边 \((u,v,d)\),如果 \(key_u \not= key_v\),那使用 \(dis_u + dis_v + d\) 更新 \(key_u\) 与 \(key_v\) 的距离。
正确性:
假设关键点 \(k\) 拓展到点 \(i\),且存在与 \(i\) 相邻的点 \(j\) 满足 \(key_j \not= k\),则如果 \(k\) 点的最优路径经过了 \(i\) 点到 \(j\) 点的路径,则一定是到达 \(key_j\) 的路径最优。因此如此更新定能保证答案正确。更新复杂度 \(O(m)\)。
随后考虑如何求得此情况下的 \(dis\) 数组与 \(key\)。
我们进行dijkstra时,首先将 \(p\) 个关键点的 \(dis\) 设为0,并一起压入优先队列。在使用 \(u\) 节点更新 \(v\) 时只需 \(key_v \leftarrow key_u\) 即可。
因为 \(n\) 与 \(m\) 同阶,总时间复杂度 \(O(n\log n)\)。
代码
struct edge {
int from, to, dis;
} res[N];
#define Aster(s) for ( register int i = head[s]; i; i = e[i].next )
#define v e[i].to
#define d e[i].dis
int head[N], mlc;
struct ep {
int to, next, dis;
} e[N<<1];
inline void adde(int f, int t, int ds) {
e[++mlc].to = t;
e[mlc].next = head[f];
e[mlc].dis = ds;
head[f] = mlc;
}
struct pid{
int id, dis;
bool operator < (const pid & b) const {
return dis > b.dis;
}
}; priority_queue<pid> que;
int dis[N], bel[N];
bool vis[N];
void dij() {
rep(i,1,p) dis[keyPoint[i]] = 0, bel[keyPoint[i]] = keyPoint[i], que.push(pid{keyPoint[i], 0});
while (que.size()) {
int u = que.top().id; que.pop();
if (vis[u]) continue;
vis[u] = 1;
Aster(u) {
if(dis[v] > dis[u] + d) {
dis[v] = dis[u] + d;
bel[v] = bel[u];
que.push(pid{v, dis[v]});
}
}
}
}
然后我们就有了单 \(\log\) 求得图上给定 \(k\) 个点间最短距离的方式了。
我们(指crs-line)突然想到一道题:这篇闲话里的第二题
我们发现一件事情
我们可以直接把与1节点相连的节点设为关键点,它们的dis设为与1节点相连边的长度,在删除1节点与连边的图上跑关键点最短路
考虑两种更新答案的方法:一种是两个关键点dis加和,按如上方法求解即可
另一种是别人的dis松弛了关键点 这时直接拿新dis加关键点与1节点连边的长度作为值更新答案
总时间复杂度 \(O(n\log n)\)
好耶爆标了
代码
#define Aster(s) for ( register int i = head[s]; i; i = e[i].next )
#define v e[i].to
#define d e[i].dis
int head[N], mlc;
struct ep {
int from, to, next, dis;
} e[N<<3];
inline void adde(int f, int t, int ds) {
e[++mlc].to = t;
e[mlc].next = head[f];
e[mlc].from = f;
e[mlc].dis = ds;
head[f] = mlc;
}
int dis[N], bel[N], con[N];
bool vis[N], del[N<<2];
struct pid {
int id, dis;
bool operator < (const pid & b) const {
return dis > b.dis;
}
}; priority_queue<pid> q;
void dij() {
while (!q.empty()) {
int u = q.top().id; q.pop();
if(vis[u]) continue;
vis[u] = 1;
Aster(u) {
if(dis[v] > dis[u] + d) {
dis[v] = dis[u] + d;
bel[v] = bel[u];
if (con[v]) ans = min(ans, dis[v] + con[v]);
q.push(pid{v, dis[v]});
}
}
}
}
rep(i,1,m) {
del[i] = 0;
get(t1), get(t2), get(t3);
if (t1 > t2) swap(t1, t2);
if (t1 == 1) {
dis[t2] = t3, bel[t2] = t2, q.push(pid{t2, t3}), con[t2] = t3;
} else {
adde(t1, t2, t3);
adde(t2, t1, t3);
}
} ans = 0x3f3f3f3f;
dij();
for (int i = 1; i <= mlc; i += 2) {
if (bel[e[i].from] == bel[v]) continue;
ans = min(ans, dis[e[i].from] + dis[v] + d);
}
if(ans == 0x3f3f3f3f) printf("-1\n");
else printf("%d\n",ans);
奇怪的dp
给定一棵深度为 \(k\) 的满二叉树。对于每个节点,向其所有祖先连无向边。请求出树上所有经过一个点不超过一次的路径条数。对非质数 \(mod\) 取模。
\(k \le 300\)。
考虑一个人类智慧DP。
设 \(f[i][j]\) 为深度为 \(i\) 的超级树,同时存在 \(j\) 条不相交的路径的方案数。不相交就是没有任何公共点。注意这里的路径不必将所有子节点覆盖。
考虑转移。
显然我们应该从两棵子树中转移过来。设 \(f[i][l]\) 为左子树方案, \(f[i][r]\) 是右子树方案,则有方案数总和 \(cnt=f[i][l] \times f[i][r]\)。我们需要转移到 \(f[i+1]\) 中。
- 什么都不做,注意这时根节点是空的。
\(f[i+1][l+r] +=cnt\) - 将根节点连到其中一棵子树的路径中。由于超级树,根节点向所有子节点都有边,这时可以任意从一条路径的两端连接,产生两种情况。
\(f[i+1][l+r] += 2 \times cnt \times (l + r)\) - 将根节点独立作为一条路径。
\(f[i+1][l+r+1] += cnt\) - 用根节点分别连接两棵子树内的一条路径。\(\times 2\) 同 2. 理。
\(f[i+1][l+r-1] += 2 \times cnt \times l \times r\) - 用根节点连接一棵子树内的两条路径。不除 2 同 2. 理。
\(f[i+1][l+r-1] += cnt \times ( l \times (l-1) + r \times (r-1))\)
答案就是 \(f[k][1]\),统计到了所有的路径。于是我们三个循环枚举 \(i,l,r\) 即可。
我们突然发现一件事情:这第二维似乎大小是 \(2^n\) 的?然后这不就炸了吗?
非也。我们需要从 \(f[1][0] = f[1][1] = 1\) dp到 \(f[k][1]\),而每次转移最多只会把路径 \(\pm\ 1\),因此考虑大于 \(k\) 的第二维是没有意义的。因此第二维有用的状态只有 \(k\) 个。
转移即可。时间复杂度 \(O(k^3)\)。
代码
get(k); get(mod);
f[1][0] = f[1][1] = 1;
rep(i,1,k-1) rep(l,0,k) for (register int r = 0; l + r - 1 <= k; r++) {
f[i + 1][l + r] = (f[i + 1][l + r] + 1ll * f[i][l] * f[i][r]) % mod;
f[i + 1][l + r + 1] = (f[i + 1][l + r + 1] + 1ll * f[i][l] * f[i][r]) % mod;
f[i + 1][l + r] = (f[i + 1][l + r] + 2ll * f[i][l] * f[i][r] % mod * (l + r)) % mod;
f[i + 1][l + r - 1] = (f[i + 1][l + r - 1] + 2ll * f[i][l] * f[i][r] % mod * l % mod * r) % mod;
f[i + 1][l + r - 1] = (f[i + 1][l + r - 1] + 1ll * f[i][l] * f[i][r] % mod * (1ll * l * (l-1) + 1ll * r * (r-1)) % mod) % mod;
}
printf("%d\n", f[k][1] % mod);
以下是博客签名,与正文无关。
请按如下方式引用此页:
本文作者 joke3579,原文链接:https://www.cnblogs.com/joke3579/p/chitchat220817.html。
遵循 CC BY-NC-SA 4.0 协议。
请读者尽量不要在评论区发布与博客内文完全无关的评论,视情况可能删除。