pog loves szh II
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1357 Accepted Submission(s): 391
Problem Description
Pog and Szh are playing games.There is a sequence with
n
numbers, Pog will choose a number A from the sequence. Szh will choose an another number named B from the rest in the sequence. Then the score will be
(A+B)
mod
p
.They hope to get the largest score.And what is the largest score?
Input
Several groups of data (no more than
5
groups,
n≥1000
).
For each case:
The following line contains two integers,
n(2≤n≤100000)
,
p(1≤p≤231−1)
。
The following line contains
n
integers
ai(0≤ai≤231−1)
。
Output
For each case,output an integer means the largest score.
Sample Input
Sample Output
题意:给你N个数和一个数P,让你找出两个数A和B,使得(A+B)%P的值最大,并且输出这个最大值
思路:拿到题,首先就是将读入的数先取模模P,然后排序。然后我就得到了N个0到P-1的数,从这些数中找出两个不同的数,他们的和范围是0到2P-2。
那么分两种情况考虑:考虑和大于等于P的情况,显然若两个数相加大于P并且模完P还是最大,那么肯定取最大的两个数(若两个数相加小于P,那么只是退化到和小于P的情况,造成多判的情况,并不会影响最后答案的正确)
然后考虑和小于P的情况:这里有两种做法。
1是遍历所有数(其实并不需要所有,这里还可以优化),将P-你正在遍历的数,然后在数组二分查找小于这个数的最大数,(这里要保证不能同时取同一个数两次)更新两个数加起来的最大值,即为答案。
2是设双指针,一头一尾,如果当前和大于等于P,尾指针-1;如果当前和小于P,头指针+1;循环条件是头指针小于尾指针。在过程中不断更新最大值。
综合考虑两种做法:二分实现起来麻烦,而且需要验证是否为同一个数,且复杂度为O(nlogn)
双指针比较好写,且复杂度为O(n);
虽然总的复杂度还是排序的nlogn,但还是推荐第二种写法
#include <cstdio>
#include <algorithm>
#define maxn 100000+5
using namespace std;
typedef long long ll;
ll a[maxn];
void read(ll& x)
{
x=0;
int flag=0;
char c=getchar();
if(c=='-')flag=1;
while(c<'0'||c>'9')
{
if(c=='0')flag=1;
c=getchar();
}
while(c>='0'&&c<='9')
{
x=x*10+c-'0';
c=getchar();
}
if(flag)x=-x;
}
int main()
{
ll n,p;
while(~scanf("%lld %lld",&n,&p))
{
for(int i=0;i<n;i++)
{
read(a[i]);
a[i]%=p;
}
sort(a,a+n);
ll ans=(a[n-1]+a[n-2])%p;
int l=0,r=n-1;
while(l<r)
{
ans=max(ans,(a[l]+a[r])%p);
if(a[l]+a[r]<p)l++;
else r--;
}
printf("%lld\n",ans);
}
return 0;
}