http://acm.hdu.edu.cn/showproblem.php?pid=5265
首先将数组中的数取模后排好序
那么数的范围就是0~p-1,两个数相加的范围0~2*p-2
1. 如果x+y<p,那么结果就是x+y
2. 如果x+y≥p,那么结果就是x+y-p
由此可以推断出,第二种情况的最大答案就是两个最大值相加减去p
第一种情况的求解可以用二分法求解
lower_bound返回的是**大于等于**查找值的第一个下标
而我们需要的值是小于p-a[i]中最大的值,所以先pos--
也可以用o(n)的方法我们从小到大枚举第一个数,同时则要从大到小枚举第二个数。
感觉还是o(n)的方法比较好些,并且之前遇到过好多次类似这种o(n)思想的题目了,所以以后要擅长使用这用方法。完整代码
首先将数组中的数取模后排好序
那么数的范围就是0~p-1,两个数相加的范围0~2*p-2
1. 如果x+y<p,那么结果就是x+y
2. 如果x+y≥p,那么结果就是x+y-p
由此可以推断出,第二种情况的最大答案就是两个最大值相加减去p
第一种情况的求解可以用二分法求解
lower_bound返回的是**大于等于**查找值的第一个下标
而我们需要的值是小于p-a[i]中最大的值,所以先pos--
for(int i=0; i<n; i++)
{
ll tmp = p - a[i];
int pos = lower_bound(a,a+n,tmp)-a;
pos--;
if(pos>=0&&pos!=i)
ans=max(ans,(a[i]+a[pos])%p);
}
也可以用o(n)的方法我们从小到大枚举第一个数,同时则要从大到小枚举第二个数。
k=n-1;
for(int i=0;i<n;i++)
{
while(i<k&&a[i]+a[k]>=p) k--;
if(k<=i) break;
ans=max(ans,(a[i]+a[k])%p);
}
感觉还是o(n)的方法比较好些,并且之前遇到过好多次类似这种o(n)思想的题目了,所以以后要擅长使用这用方法。完整代码
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#include<stack>
#define bug puts("bugbugbug");
#define ll long long
using namespace std;
ll n,p;
ll a[110000];
int main()
{
while(cin>>n>>p)
{
for(int i=0; i<n; i++)
{
scanf("%I64d",&a[i]);
a[i]%=p;
}
if(n==2)
{
cout<<(a[0]+a[1])%p<<endl;
continue;
}
sort(a,a+n);
ll ans=(a[n-2]+a[n-1])%p;
k=n-1;
for(int i=0; i<n; i++)
{
ll tmp = p - a[i];
int pos = lower_bound(a,a+n,tmp)-a;
pos--;
if(pos>=0&&pos!=i)
ans=max(ans,(a[i]+a[pos])%p);
}
cout<<ans<<endl;
}
return 0;
}