2024杭电多校第5场
5
1002 Array-Gift (hdu7482)
某种意义上的找规律题?
若序列中存在 \(a_i = gcd(a_1,a_2,...a_n)\),则显然 \(a_i\) 为序列中的最小值,可通过 \(n-1\) 次取模操作,将其他数变成 \(0\),由于原序列中 \(a>0\),不存在更少的操作次数。若不存在上述 \(a_i\),可通过 \((a_i + x)\space mod\space a_j\) 两步操作凑出其他数的 \(gcd\),故最多操作次数为 \(n + 1\). 接下来讨论操作 \(n\) 次的情况,这其中必有 \(n-1\) 次取模操作,因此只需考虑另外一次操作的类别。对原序列升序排序,设其 \(gcd\) 为 \(g\).
1)若进行 \(a_i\space mod\space a_j = b\),使当前的 \(gcd = g'\) 存在于序列中,则 \(b=g'\) 或 \(g'|b\). \(b=g'\) 时有 \(b|a_j\),故 \(b|a_i\) 成立,\(b|g\) 即满足要求。由于对其他数提前取余不会改变 \(g'\),此情况下不用考虑操作次序;\(g'|b\) 时由升序排列 \(g' = a_1\),若 \(a_1|b\),则有 \(a_1 | a_i\),即对原序列已有 \(a_1 = g\),不符合条件。
2)若进行 \(a_i + x = c\),则 \(c=g'\) 或 \(g'|c\). \(c=g'\) 时必有 \(i=1\),\(a_1 \leq gcd(a_2,a_3,...a_n)\) 时可凑出满足条件的 \(c\);\(g'|c\) 时 \(g' = a_1\),注意到 \(gcd(g',a_j)\leq g'\),对更少的数求 \(gcd\) 显然更优,因此可预先将所有 \(a_i\space mod\space a_j = 0\) 操作完毕。
1006 猫罐头游戏 (hdu7486)
和wyq愉快地乱猜一气,还好最后过了。
设三堆猫罐头数量为 \(a,b,c,\) 失败局面为 \(a=b=c=1\),当 \(a,b,c\) 都为奇数时,要么已经处于失败局面,要么无法构造出任何 \(a=b=c=1\) 的情况使对方猫猫失败,而 \(a,b,c\) 中有1个或2个偶数时,可以给对方构造出三个奇数的状态,因此 \(a,b,c\) 为奇数时处于必败态,有1个或2个偶数时处于必胜态。
当 \(a,b,c\) 全部为偶数时,无法一步构造出全为奇数的必败态。已知出现奇数时的胜负情况,任何一只猫猫都不会把必胜态主动交给对方,因此最优策略是尽可能停留在偶数状态,即以2为单位分罐头。已知 \(a=b=c=2\) 时,因无法维持偶数,先手必败,于是该局面等价于将 \(a,b,c\) 同时除以2的情况,多次除以2直至出现奇数,即可按照之前的规律得出结果。
1008 猫咪们狂欢 (hdu7488)
猫猫题好评,写不出来差评(好像是我太菜了导致的)
赛时wyq:?边权限制这么小有什么用?
我:(瞎猜)说不定是网络流呢。
wyq:《怎么可能是网络流啊!》
好吧其实知道用网络流也写不出来。网络流还是五一学的,什么久远的记忆)
首先本题运用了网络流的经典模型:最大权值闭合图。给定一张有向图,其中每个点都有或正或负的权值,求点权和最大的子图,使子图中各点的后继点(如果存在后继点)同样在子图中。解法是建立总源点 \(st\) 与总汇点 \(ed\),设 \(i\) 点点权为 \(val_i\),若 \(val_i>0\),则由 \(st\) 至 \(i\) 连边,边权为 \(val_i\);若 \(val_i<0\),则由 \(i\) 向 \(ed\) 连边,边权为 \(-val_i\);原图中的连边保留,边权设为 $\infty $. 计算该图的网络最大流,答案即所有正数点权和减去最大流。
证明如下:网络流模型中最大流等于最小割,所建新图中最小割相当于将原图中所有点分割为两部分,其中原图的连边因边权为 $\infty $,不可能作为最小割的一部分,因此和 \(st\) 相连的点不存在被分割开的后继节点,满足题目要求。最终答案为正数点权和 \(-\) 未选的正数点权和 \(+\) 选择的负数点权和,未选中的正数相当于断开其与 \(st\) 的连边,选中的负数相当于断开其与 \(ed\) 的连边,需要使断开的边权尽可能小,求得的最小割符合条件。(其实今天才第一次见这个模型,也不知道我上回学了个啥)
回到本题,一只狂欢猫只有待在树1或树2上两种选择,可借鉴该模型的思路,先将所有猫放在树1上,算出目前的狂欢值,再将一部分猫转移到树2,狂欢值的变化量即可用正负点权表示。对每只猫猫而言,从树1到树2的变化即树2增加的狂欢值 \(-\) 树1减少的狂欢值,两者不可分开计算,符合最大权值闭合图模型中后继节点不可断开的要求。首先对节点 \(1\) 至 \(k\),\(val_i\) 即第 \(i\) 只狂欢猫在树1上贡献的权值相反数,表示从树1到树2过程中损失的狂欢值;对于树1上每一条有效边(两端都有狂欢猫的边),其权值 \(w\) 被两侧端点各计算了一次,因此再新建一个节点 \(j\) 与两侧端点连边,使 \(val_j = w\),以弥补多算的损失;对于树2上的有效边,新建节点 \(x\) 与两端点连边,使 \(val_x = w\),即转移过程中获得的狂欢值。根据最大权值闭合图的定义,若 \(1\) 至 \(k\) 被选入子图中,由于其权值为负数,同时将其前驱节点选入才可能更优,而此时与之相连的其他后继节点(相邻的狂欢猫猫)也会被选入子图,符合情境要求。最后答案即树1原先总权值 \(+\) 最大变化量(子图的最大权值)。
Dinic算法求网络最大流(写的时候差点没找到自己之前的板子,乐):
void bfs() {
for(int i = st; i <= ed; i++) l[i] = -1;
queue <int> q;
l[st] = 0;
q.push(st);
while(!q.empty()) {
int x = q.front();
q.pop();
for(int i = 0; i < v[x].size(); i++) {
int t = v[x][i].t, w = v[x][i].w;
if(w > 0 && l[t] < 0) {
l[t] = l[x] + 1;
q.push(t);
}
}
}
}
int dinic(int i, int fl) {
if(i == ed) return fl;
for(; it[i] < v[i].size(); it[i]++) {
int t = v[i][it[i]].t, w = v[i][it[i]].w, r = v[i][it[i]].r;
if(w > 0 && l[t] > l[i]) {
int d = dinic(t, min(fl, w));
if(d > 0) {
v[i][it[i]].w -= d;
v[t][r].w += d;
return d;
}
}
}
return 0;
}
int main() {
//...
int flow = 0;
for(;;) {
bfs();
if(l[ed] < 0) break;
for(int i = st; i <= ed; i++) {
it[i] = 0;
}
for(;;) {
int f = dinic(st, MAX);
if(f <= 0) break;
flow += f;
}
}
return 0;
}
建图连边操作,多参考std是好事,现在这个比我的1.0版本好看且简单多了)
for(int i = 1; i <= k; i++) {
int u;
scanf("%d", &u);
yes[u] = i;
}
int now = 0;
for(int i = 1; i < n; i++) {
int x, y, w;
scanf("%d%d%d", &x, &y, &w);
if(yes[x] && yes[y]) {
now += w;
val[yes[x]] -= w;
val[yes[y]] -= w;
z++;
val[z] = w;
add(z, yes[x], MAX);
add(z, yes[y], MAX);
}
}
for(int i = 1; i < n; i++) {
int x, y, w;
scanf("%d%d%d", &x, &y, &w);
if(yes[x] && yes[y]) {
z++;
val[z] = w;
add(z, yes[x], MAX);
add(z, yes[y], MAX);
}
}
st = 0, ed = z + 1;
int sum = 0;
for(int i = 1; i <= z; i++) {
if(val[i] > 0) {
sum += val[i];
add(st, i, val[i]);
}
else add(i, ed, -val[i]);
}
1013 飞行棋 (hdu7493)
犯困的时候迷迷糊糊推了个式子,居然过了,真好。观察到飞行棋到达终点的概率不是古典概型,考虑按步计算,设 \(i\) 步刚好到达终点的概率为 \(p_i\),有 \(p_1 = 1/n\),而 \(i>1\) 时无法回到 \(0\) 位置,即扔出 \(n\) 时不可能直接到达终点,无需分类讨论,有 \(p_i = (1 - \sum\limits_{j = 1} ^ {i - 1} p_j) * (\frac{1}{n} +\frac{1}{n(n - 1)})\),即先前一直未到达终点与此时到达终点的概率之积,其中 \(\frac{1}{n}\) 为直接走到终点的概率,\(\frac{1}{n(n - 1)}\) 即先扔到 \(n\) 再使用赠送次数走到终点的概率。\(m\) 次操作内的期望次数 \(e_m = \sum\limits_{i = 1} ^m i*p_i\),化简后可用等比数列求和公式计算,\(m\to \infty\) 时即无穷递缩等比数列,其和趋近于一定值,计算得 \(e = n - 1 +1/n\).