Atcoder abc229
https://atcoder.jp/contests/abc229/tasks
G - Longest Y
一个包含字符’Y’和’.’的长n字符串S,
可以操作[0,k] 次,交换S中的两个相邻字符
问可以得到的最终S的内部最长的连续Y的长度
范围
n 2e5
k 1e12
2s
1024mb
我的思路
考虑移动
最终假设是[l..r]
那么对于初始这些y的位置的大范围是[l0..r0]
那么一定可以分成两部分
[l0..m0][m0+1..r0]
一部分向右,一部分向左
显然有个点不需要动
如果选定了第i个点p[i]和期望个数c那么,移动代价为min( 左侧k0, 右侧k1个), k0+k1+1=c
= min(sum(p[i]-k0..p[i]-1) - sum(p[i-k0]..p[i-1]) + sum(p[i+1]..p[i+k1]) - sum(p[i]+1..p[i]+k1))
换个角度
所有值变成p[i]-cnt1[i]
那么就是找一个值, 尽量多的数变成它, 且代价和 <= K
显然每多一个,代价的增量是非严格递增的
是个凸函数(下凹)
但感觉, 这样看起来, 其实左侧右侧影响不大,而是距离影响更大,
所以直接枚举中点,二分距离(选定的点的最大距离) => 去计算距离和范围,以及点数范围
这里 < 距离的必选, >距离必定不选, =距离可选可不选
似乎就没了?
代码
https://atcoder.jp/contests/abc229/submissions/34483869
1 |
|
H - Advance or Eat
n 行n列棋盘,每个格子可能三种状态 空/白/黑, 题目提供
T和S交替游戏
T, 将一个白色向上移动一格(不能重叠不能出棋盘) 或者 吃掉一个黑色
S, 将一个黑色向上移动一格(不能重叠不能出棋盘) 或者 吃掉一个白色
无法行动的输掉
范围
n <= 8
2s
1024mb
我的思路
显然需要博弈论
然后不同列之间没有关系
3^8 = 6561
如果每个状态算出sg函数也就做出来了?
但这里好像不是公平的游戏
想让对手不能走
通过移动自己的向上并不会产生影响, 因为如果原来在前面的不受影响, 在后面的要么不受影响, 要么可移动的长度更长
你能走的步数, 在不考虑被删除的情况下, 你能走的步数就是每个向上移动的步数+对手棋子数
而对手的棋子数最终都会变成你的步数
但你向上移动, 可以通过移动掉对手的棋子来增加步数, 也会受到对手的移动而减少
因此显然如果你当前指定一列要移除一个,几个对手同色的连续(可以有空格,没有其它颜色), 你移动掉的一定是最下方的那个, 更好的方案不会比这个好
f(T/S) = 对面个数+ sum( pos[i] - cnt[i])
, 位置-同色第几个
游戏结束时,一定一方的棋子被完全移除了
每次T 做移动,会让一个pos-1, f(T) -1,
每次T 做删除,会让对面一个棋子消失f(T) -1,f(S)中移除某个(pos-cnt)
S 是对称的
例如游戏结束时,B被删完了,W还有剩余,f(T) = 0, f(S) > 0
T 输, 所以
可以看成每次你的值-1,你可以降低对面一个值
谁先0谁输
考虑f(T) 和 f(S) 的差的变化
所以直接贪心,每次删除对手一个最大的即可?
写了以后发现并不对
https://atcoder.jp/contests/abc229/submissions/34484702
问题在于, 当需要移W或删B时
B都是无法移动,意味删除代价为1, 移动也是1, 删B->对手删->无法移动 肯定是比 移动->对手删->删B 多步的,而这种情况, 移动不一定是能操作的
题解
哦!!! 还是SG
显然根据SG的知识, DAG上面一些点上有多个棋子, 交替操作,每次沿着一个边移动一个棋子, 不能操作的输掉
然后就是mex 和sg函数
然后也是需要Impartial game, 可以转换成DAG, 否则需要其它的额外方法
如何处理 Partisan Games
考虑同样DAG,但是边染色了(黑/白), 但是第一个玩家,只能走白边, 第二个玩家只能走黑边
但是是对每个点给予一个评估实数
对于第一个玩家(只走白)来说,每个点的值越大越好, 对于第二个玩家(只走黑)来说,每个点的值越小越好, 同时每个值随着走白边下降,走黑边增加
如何计算评估值
如果连出的边的点存在未定义,则当前未定义
否则的话 max(白出点) < eval(当前) < min(黑出点), 如果不存在这样的值 则当前为未定义
当上述存在方案时, 如果有整数满足, 则定义为绝对值最小整数
否则用分母为2的幂次,且分母最小的分数来表示
如何判断赢家
计算所有点上的值的和, 如果为正,第一个赢, 如果 <= 0, 则第二个赢
证明
对于所在的和为正时, 轮到第一个玩家操作
如果 为正, 那么可以找到一个白色路径, 让结果 >= 0
假设和的2的幂次为w, 则加和中至少一个棋子所在的分母的2的幂次w1大于等于这个幂次w(-1/2+1/2 = 0/1,-1/2+1=1/2), 那么让这个值沿着白边走, 则它的变化就是1/2^(>=w1)(因为上面的分数赋值的设计关系,最大的白色和它关系), 所以 ?/2^w - 1/2^(>=w1) >= 0
max(=1/4) < eval < min(1) => eval = 1/2
如果 为<= 0, 则一次白色边移动后 一定为负数
对于第二个玩家所在
走黑边是同理的,
因此 如果 正 => (>=0) => 正 => (>=0) ...
如果 (<=0) => (<0) => (<=0) => (<0) ...
可以看成不变量会保持了
至此证明了, 如此设置eval,以及 先后手的目标分别是让值更大, 和让值更小, 会有这个结果, 一个是 单次操作和总答案的关系是否有局部性? 第二格式为啥这个目标和原不能移动 是等价?
如何和原题联系起来?
TODO 虽然移动和结束状态等价, 为啥分别追求larger和smaller是等价的?
追求larger和smaller 为何与单步的保证上面变化序列等价
显然 如果 正 -> (<0)
那么对手一定不会让你再回到正, 所以为了最大,一定要正 => (>=0)
, (对称显然)
但是这里并没有说一定要 正 => (最大的>=0)
, 上面相当于证明了方案存在性
就是如果一个追求larger,一个追求smaller, 那么必然是按照这两种走法去走, 所以都能维持自己的状态
原题
就是不同列之间无关, 建立3^n的图, 然后算每点的eval值
然后 需要证明任何点都能有值, 其实可以按照DAG的拓扑顺序赋值, v 以前的假设都有值了
那么需要证明的就是 最大白出边v->a < 最小黑出边v->b
- 如果这两个边k 对应操作都是 删除一个对手的子, 那么有v 吃两个子的状态c,因为 v白a黑c, v黑b白c,满足 eval(a) < eval(c) < eval(b)
- 如果a和b对应的实际操作 不会互相影响, 可以先a再b和先b再a,都和上面同理
- 考虑会互相影响, 也就是一个删掉对手棋子(a), 另一个操作恰好是移动这个棋子(b), 但这种情况会出现 b -> a的边, 因此eval(a) < eval(b)
因此证明了可以建图,且每个点都有值
学了下snuke的代码
https://atcoder.jp/contests/abc229/submissions/27565297
有eval(状态) = -eval(状态翻转B/W)
因为 从状态在DAG上走 的结构, 和其翻转的状态在DAG上走的结构对称
所以如果它依赖的点也满足 互为相反数, 那么它就满足互为相反数(根据依赖关系, 每次取2幂次最小的绝对值最小,得证)
然后这里用long long 而不是double
这里想知道的是one = 1ll << 30 有啥办法推得吗, 虽然实际运算可以得到最高幂次, 如果不算的话有办法推得吗?
代码
TODO url
1 |
|
总结
G
没啥难的
H
算是会了基础的SG函数, 但是对于这种Partisan Games还是没学过, 又学了一手, 另外加深一下对博弈论建立DAG的理解
然后这里的 eval存在性需要保证
然后上面证明的细节还是不会(据说要 surreal number相关知识, orz)
TODO < winning ways for your mathematical plays >
TODO < surreal number >