【题解】CF1411D Grime Zoo
本题解约等于CF官方题解的翻译版+比较通俗易懂的解释+博主的胡诌八扯
题意:
一个01字符串,它当中每一个01子序列会获得x个愤怒评价(angry comment),每个10子序列会收到y个愤怒评价
子序列:可以不是连续的一段 比如011001有5个01子序列,4个10子序列(参考最长上升子序列)
这个字符串当中有一些尚未确定的数,用问号(?)表示
你的任务确定这些问号的值,使得愤怒评价尽可能少
输入这个字符串和x y
输出最少的愤怒评价数量
字符串长度n<=1e5
x,y<=1e6
题解
(下面的推导有点烦人,而且难以让人发现真正的思路时怎么来的,所以建议直接拉到最后结合更新的部分内容来看)
两个相邻的问号,设它们分别在l 和 r(l<r)
如果a[l]=0,a[r]=1
总愤怒评论数可以这样统计
l位置的0和(l,r)内部的1 : x * c1[l,r]
(l,r)内部的0和r位置的1 : x * c0[l,r]
l,r和[l,r]外部数字组成的二元组的贡献 : out
除去l r以外,其他数字的贡献(不受a[l]和a[r]的影响,优化时可以不考虑) : other
angry comment=x * c0[l,r]+x * c1[l,r]+out+other=x*(r-l-1)+out+other
同理,a[l]=1,ar[r]=0时
angry comment=y * c1[l,r]+y * c0[l,r]+out+other=y*(r-l-1)+out+other
注意到out和other在两种情况下是相等的,这里只需要优化第一项
即比较x*(r-l-1)和y*(r-l-1)那个更小
显然,直接比较x和y哪个小就行了
x<y时,对于两个相邻的'?',01优于10
x>y时,10优于01
看到这里难免有疑问,这样类似于爬山算法或者梯度下降法的优化,会不会陷于局部最优解?
会,但有办法解决
不妨假设x<y
对于任意可行解
比如0011011000
可以这样优化
0011011000
0011010100
0011010010
0011010001
0011001001
0011000101
0011000011
...
0000001111
你会发现优化的过程就是不断地把1后移(移动过程中,1的数量保持不变)
最优解一定前面全是0,后面全是1(如果不是的话,那么一定可以把0前面的一个,1后移一位,使答案优化)
但前缀0的长度是多少呢?很简单,枚举一下就好了,O(n)的
如果x>y,情况类似,反过来就好了
如果x=y 可以发现 如果0和1 的数量不变,那么答案是不变的,不妨按照x<y处理
回顾一下这一题的思路 先找到了一个优化的方法,确定了哪些一定不是最优解,以及 如果是最优解,那么它一定是什么样的,这样做可以缩小枚举范围,
一旦这个枚举范围可以接受,那么直接枚举就好了
说句题外话,这题的思路有点类似于求多元函数最小值的过程
对于一个定义在Rn上的可导函数f(x),如果▽f(x*)不是零向量,那么存在ε,使得f(x*-ε▽f(x*))<f(x*),所以x*一定不是最优解
如果argmin[x] f(x)存在,那么它一定满足▽f(x)=0
列个方程求出▽f(x)=0的所有解,如果只有有限数量的解,那么挨个枚举就完事了
UPD 2021-3-27
这里提供一个比较简单的角度:
当a里面1(或者0)的数量不变时,显然01序列和10序列的数量和是不变的
如果我们交换一对0和1(1在前面还是0在前面无所谓)
那么由于01和10的总和不变,那么可能会导致01和10的数量此消彼长
如果1在前,那么10减少,01增加,否则01减少,10增加
如果x<y,那么显然要让01尽可能地多,那么把尽可能把1放在后面就是最优解

浙公网安备 33010602011771号