codeforces 484 B Maximum Value 排序+二分 + 数学

来源:互联网 发布:淘宝韩版情侣装学生 编辑:程序博客网 时间:2024/05/15 07:01

链接:http://codeforces.com/contest/484/problem/B
题意:给定长度为n的序列,要求序列中 ai % aj 最大的值是多少。
思路:
给定的n为105,直接暴力O(n2)肯定是不行的。
首先可以明确,aj如果越大的话,那么取模后的值就可能越大,因为取模后只能在0~aj -1 这些数之中了。
又因为在这道题中,序列的顺序并没有用,所以考虑进行排序,从小到大,然后从大的开始取。
对于同一个aj的话要使取模后的数尽可能的大的话,ai应该是出现在小于aj的某个倍数的第一个数。那么我们就可以在序列中二分查找大于等于 aj k倍的数,以及小于k+1 倍 的第一个数。(查找k倍,防止少了模为0的情况)
确定算法,从大到小枚举序列中的元素,从一倍开始,每次都二分查找。如果已经在这个序列中找不到大于等于 k * aj 的数,那么就停止,枚举下一个元素。但是发现这样可能会超时,因为如果这个序列中只有很少的元素,但是这些数直接差距非常大,比如1 100000 ,那么这样枚举倍数的话就一定会枚举到100000上,但是会发现从2~100000找到的都是100000这个数,都是重复的。
所以考虑直接用迭代这个倍数,如果找到第一个大于等于k*aj的数 ap,那么将 j 变为ap/aj + 1,防止下次又找到ap这个数。

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;#define M 1000009#define INF 0x3f3f3f3fint a[M];int n;int main(){    //freopen("in.txt","r",stdin);    while(scanf("%d",&n)==1)    {        for(int i = 0;i< n;i++)            scanf("%d",&a[i]);        sort(a,a+n);        int ans = -INF;        for(int i = n-1;i >= 0;i--)        {            for(int j = 1;;)            {                int p = lower_bound(a+i,a+n,j*a[i]) - a;                int q = lower_bound(a+i,a+n,(j+1)*a[i]) - a - 1;                if(p == n) break;                ans = max(a[p]%a[i],ans);                ans = max(a[q]%a[i],ans);                j = a[p] / a[i] + 1;                //直接迭代到有用的倍数上,避免出现 1 1000 这样无用循环太多的情况            }            if(ans > a[i]) break;        }        printf("%d\n",ans);    }    return 0;}
0 0