题解:CF2110F Faculty

不失一般性的,我们设 x ≤ y x \le y xy

从最简单的情况考虑,当 x = y x = y x=y 时, f ( x , y ) = 0 + 0 = 0 f(x,y) = 0 + 0 = 0 f(x,y)=0+0=0。以下均为 x < y x < y x<y 的情况,推推式子可知:

f ( x , y ) = x   m o d   y + y   m o d   x = x + y − ⌊ x y ⌋ y − ⌊ y x ⌋ x f(x,y) = x \bmod y + y \bmod x= x + y - \lfloor\frac{x}{y}\rfloor y - \lfloor\frac{y}{x}\rfloor x f(x,y)=xmody+ymodx=x+yyxyxyx

由于 x < y x < y x<y,式子可以进一步化简:

f ( x , y ) = x + y − ⌊ y x ⌋ x f(x,y) = x + y - \lfloor\frac{y}{x}\rfloor x f(x,y)=x+yxyx

x < y x < y x<y 可知 ⌊ y x ⌋ ≥ 1 \lfloor\frac{y}{x}\rfloor \ge 1 xy1,于是可以得到以下观察:

x ≤ x + y   m o d   x = f ( x , y ) = y − ( ⌊ y x ⌋ − 1 ) x ≤ y x \le x + y \bmod x = f(x,y) = y - (\lfloor\frac{y}{x}\rfloor - 1)x \le y xx+ymodx=f(x,y)=y(⌊xy1)xy

分析可知,当 x ∣ y x \mid y xy 时不等式左侧取等;当 x < y < 2 x x < y < 2x x<y<2x 时不等式右侧取等。

接下来考虑对于任意前缀长度为 k k k 的答案是怎么取到的。当 n = 1 n = 1 n=1 时答案显然为 0 0 0 n = 2 n = 2 n=2 时为 a 1   m o d   a 2 + a 2   m o d   a 1 a_1 \bmod a_2 + a_2 \bmod a_1 a1moda2+a2moda1。对于 n ≥ 3 n \ge 3 n3 的情况,考虑 f ( x , y ) f(x,y) f(x,y) f ( y , z ) f(y,z) f(y,z) 满足 x ≤ y ≤ z x \le y \le z xyz,由不等式可知 x ≤ f ( x , y ) ≤ y ≤ f ( y , z ) ≤ z x \le f(x,y) \le y \le f(y,z) \le z xf(x,y)yf(y,z)z,因此可以证明前缀长度为 k k k 的最大值里一定有一个数取到 max ⁡ i = 1 k { a i } \max \limits_{i = 1}^k\{a_i\} i=1maxk{ai}

再由不等式可知存在 y ≥ 2 x y \ge 2x y2x 的情况时才会使得答案变得不确定,而这种情况最多只会有 log ⁡ \log log 次,因此直接暴力更新即可,总时间复杂度 O ( n log ⁡ n ) O(n \log n) O(nlogn)

代码如下:

void solve ()
{
    int n = read ();
    vector <int> a (n + 1),ans (n + 1,0);
    for (int i = 1;i <= n;++i) a[i] = read ();
    int mx = a[1];
    for (int i = 2;i <= n;++i)
    {
        if (a[i] > mx)
        {
            if (a[i] >= mx * 2) {for (int j = 1;j < i;++j) ans[i] = max (ans[i],a[i] % a[j] + a[j] % a[i]);}
            else ans[i] = a[i];
            mx = a[i];
        }
        else ans[i] = max (ans[i - 1],mx % a[i] + a[i] % mx);
    }
    for (int i = 1;i <= n;++i) printf ("%d ",ans[i]);
    puts ("");
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值