【训练题58:数学 + 想法】Maximum Value | CF484B

题意

  • Maximum Value | CF484B
    2100 2100 2100
    给你长度为 n n n 的序列 A [ 1 , n ] A[1,n] A[1,n]
    1 ≤ i , j ≤ n 1\le i,j\le n 1i,jn A [ i ] ≥ A [ j ] A[i]\ge A[j] A[i]A[j] , 求 A [ i ] % A [ j ] A[i]\% A[j] A[i]%A[j] 的最大值
  • 1 ≤ n ≤ 2 × 1 0 5 1\le n\le 2\times10^5 1n2×105
    1 ≤ A [ i ] ≤ 1 0 6 1\le A[i]\le 10^6 1A[i]106

思路

  • 这题真的绝了…
    首先暴力肯定没法做。我们考虑化简一下式子:
    A [ i ] % A [ j ] A[i]\%A[j] A[i]%A[j] 就是 ∃ k ∈ Z \exist k\in Z kZ,满足 A [ i ] = x + k × A [ j ] A[i]=x+k \times A[j] A[i]=x+k×A[j]
    我们需要求的就是 max ⁡ { x } \max\{x\} max{x}
  • 我们可以暴力枚举 k k k ,也就是暴力枚举 k × A [ j ] k\times A[j] k×A[j]
    然后怎么去获得最大的 x x x 呢?
    其实就是找到在 [ ( k − 1 ) A [ j ] , k × A [ j ] ] [(k-1)A[j],k\times A[j]] [(k1)A[j],k×A[j]] 区间里面最右边的数字 y y y
    然后把这个 y y y 去处理一下 y % A [ j ] y\% A[j] y%A[j] ,更新这个最大值
  • 怎么找这一段区间里的最靠右的值呢?
    因为我们数字很小 < 1 0 6 <10^6 <106 ,我们就记一个 p r e [ i ] pre[i] pre[i] 数组,表示距离 i i i 且在 i i i 左边的最大的位置 j j j
    然后就可以了

代码

  • 时间复杂度: O ( N log ⁡ N ) O(N\log N) O(NlogN)
bool have[MAX];
int pre[MAX];
int YOU = 1000000;
int main()
{
    int n;n = read();
    for(int i = 1;i <= n;++i){
        int t = read();
        have[t] = 1;
        pre[t]++;
    }

    for(int i = 1;i <= YOU;++i){
        if(pre[i])pre[i] = i;
        else pre[i] = pre[i-1];
    }
    int ans = 0;
    for(int i = 1;i <= YOU;++i){
        if(!have[i])continue;
        for(int j = i + i;j <= YOU;j+=i){
            ans = max(ans,pre[j-1] % i);
        }
        ans = max(ans,pre[YOU] % i);
    }
    cout << ans;
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值