pog loves szh II
Accepts: 219
Submissions: 834
Time Limit: 4000/2000 MS (Java/Others)
Memory Limit: 65536/65536 K (Java/Others)
问题描述
pog在与szh玩游戏,首先pog找到了一个包含 n 个数的序列,然后他在这 n 个数中挑出了一个数A,szh出于对pog的爱,在余下的 n−1 个数中也挑了一个数B,那么szh与pog的恩爱值为 (A+B) 对 p 取模后的余数,pog与szh当然想让恩爱值越高越好,并且他们想知道最高的恩爱值是多少。
输入描述
若干组数据(不超过 5 组 n≥1000 )。 每组数据第一行两个整数 n(2≤n≤100000) , p(1≤p≤231−1) 。 接下来一行 n 个整数 ai(0≤ai≤231−1) 。
输出描述
对于每组的每个询问,输出一行,表示pog与szh的最大恩爱值。
输入样例
4 4 1 2 3 0 4 4 0 0 2 2
输出样例
3 2
由于序列中的数可能超过P,所以将所有的数读入后进行取模操作。之后将取模后的所有数从小到大排序。题目要求我们求不同位置的两个数的和在取模意义下的最大值,而现在所有数都是小于P且排好序的。因此设我任意选了两个数是X和Y,显然0≤X+Y≤2P−2。若X+Y<P,则这次选数的答案就是X+Y,若X+Y\gepP,则答案是X+Y−P。
那么我们可以这样做:将其中最大的两个数字相加取模,设为一个可能的答案记录在ANS中。这个答案是第二种情况的最大值。再对排序好的序列进行枚举,对每个枚举到的数,找出最大的数,使这个数与枚举到的数相加后的和最大且小于P,将之记为可能的答案并于之前找到的最大值ANS进行比较。这个答案是第一种情况中的可能的最大值。而普通的枚举是要超时的,但是我们发现如果从小到大枚举第一个数,那么另一个匹配的数显然是从大到小的,因此可以用一个NOW记录当前另一个匹配的数的位置,每次枚举时NOW递减至符合条件。可以做到O(n)的时间复杂度。
综上所述,时间复杂度为快速排序的O(nlogn),空间复杂度为O(n)。注意一些特殊情况如同一个位置不能多次选。
#include <iostream>
#include <cstdio>
#include <cstring>
#include<algorithm>
using namespace std;
int a[100010];
int main()
{
int n,p;
while(cin>>n>>p)
{
for(int i = 1;i<=n;i++)
{
scanf("%d",&a[i]);
a[i]%=p;
}
sort(a+1,a+n+1);
int ans = (a[n]+a[n-1])%p;
int last = n;
for(int i = 1; i<=n;i++)
{
while(last && a[last]+a[i]>= p) last--;
if(last) ans = max(ans,a[last]+ a[i]);
}
cout<<ans<<endl;
}
return 0;
}