CF889E题解

Problem - 889E - Codeforces *3000

修正

感谢学长 fs 指出状态数原因解释的错误。

题意

给一个序列,对于一个非负整数 x,有一个式子:

xmoda1+xmoda1moda2+...+xmoda1moda2...modan

求出上式的最大值。

思路

先去寻找题目的性质。

首先 x 的值单调不增,然后如果当前 x 的值小于 ai 则对 x 无影响。

对于上述两条,我们首先能够总结出一点:一定存在一个答案区间 [l,r],其中 ansl=ansr=al1。说人话就是首先答案是一段一段的递减区间,然后一定有一段区间的值顶着对应区间的上界。因为如果没有,则可以至少令当前 x+1,然后答案更大。然后就是 x+1 的操作的正确性是因为余数性质:x+yx%p+y%p(modp),所以只要操作后 x 小于 p 后面区间就不会变成零,并且我如果将最初x+1,那么所有位置x都会加一,答案也都会加一。

然后对于这道题有一个显然的暴力 dp。我们令 fi,j 表示计算到位置 i 当前 x 值为 j 的最大值,转移显然,复杂度是 O(n×a1)

考虑能否优化状态。因为答案区间是一段一段的递减,其实我们枚举 j 的时候就会发现最下面的答案是 i×j,然后上面变成一段更小的单调不增的区间。然后根据之前发现每个位置对应的 x 同加同减,也就是说他们的相对值不变,所以如果我们不去维护最后的答案而是只维护上层的答案,那么更新(转移)上面的答案就是 O(1) 的。比如我转移状态需要修改 x 时,我只需要把区间整体答案修改即可。

所以我们得到了最终的 dp,设 fi,j 表示计算到位置 i 当前 x 值为 j每个 x 大于 j 的部分的和,最后答案就是 max0i<an{fn,i+n×i}。转移时对于 fi,j 分成两种情况考虑:

  1. 直接转移到 fi+1,j%ai+1:这时 j 变小,答案加上 jj%ai+1 的高度;
  2. 每次新维护一个 fi+1,ai+11:答案加上的高度类比第一种即可。

存在第二种转移是因为性质一告诉我们一定会有一个 x=ai1,所以每次需要维护。

关于复杂度的话,考虑对于每个 i,至多存在 0,1,2...,ai1 一共 ai 种状态,所以初始状态可看成 n 种;每次转移会将 j 转移到 j%ai 上,又因为每次取模 j 至少减半,所以状态是 nlogx 的。然后实际 dp 的时候,第一维滚掉,第二维发现 j 太大用 map 存,然后 map 也有一只 log,所以时间复杂度是 O(nlogxlogn)

代码

signed main(){
    n = rd(), res[p = rd() - 1] = 0;
    for(int i = 2; i <= n; ++i){
        p = rd();
        for(map < ll , ll > :: iterator it = res.lower_bound(p); it != res.end(); res.erase(it++)){
            ll j = (*it).first, f = (*it).second;
            res[j % p] = max(res[j % p], f + (i - 1) * (j - j % p));
            res[p - 1] = max(res[p - 1], f + (i - 1) * ((j + 1) / p * p - p));
        }
    }
    for(map < ll , ll > :: iterator it = res.begin(); it != res.end(); it++)ans = max(ans, n * (*it).first + (*it).second);
    printf("%lld", ans);
    return 0;
}
posted @   Lyrella  阅读(67)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示