LG7521 [省选联考 2021 B 卷] 取模
给定 \(n\) 个正整数 \(a_i\),请你再其中选出三个数 \(i,j,k(i\neq j,i\neq k,i\neq k)\),使得 \((a_i+a_j)\bmod a_k\) 的值最大。
复杂度不太会证,说一下做法。
顺序不影响答案,先排序一下。
模数大的时候答案更大的可能性会更高,所以我们从大到小选择模数。对于每个模数,计算出剩余的数对其取模的值组成的新的序列。容易发现答案的和要么是两个数的和小于模数,或者大于等于模数,小于模数的两倍。
- 两个数的和小于模数,对新序列排序之后,确定一个数时就能通过二分查找很快求出和最大值。
- 两个数的和大于模数,可以发现取到这个最大的和就是新序列的最后两项之和。
然后加上一些不难想的剪枝即可。据说复杂度是 \(O(n\log ^2n)\) 的(如果值域与 \(n\) 同阶)。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef pair<ll,ll>ttfa;
inline ll read(){
ll x=0,f=1;char ch=getchar();
while(ch<'0'||'9'<ch){if(ch=='-')f=-1;ch=getchar();}
while('0'<=ch&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*f;
}
using namespace std;
const int N=200005;
int n,a[N],ans,b[N];
int main(){
n=read();
for(int i=1;i<=n;++i)a[i]=read();
sort(a+1,a+1+n);
for(int i=3;i<=n;++i)
ans=max(ans,(a[i-2]+a[i-1])%a[i]);
for(int i=n;i>=1&&a[i]>ans;--i){
if(a[i]==a[i+1])continue;
int tot=0;
for(int j=1;j<=n;++j)
if(j!=i)b[++tot]=a[j]%a[i];
if(tot>=2)ans=max(ans,(b[tot]+b[tot-1])%a[i]);
sort(b+1,b+1+tot);
for(int j=tot;j>=1;--j){
int loc=upper_bound(b+1,b+j+1,a[i]-b[j]-1)-b-1;
//printf("%d %d %d\n",a[i],j,loc);
if(loc<1)continue;
if(loc>=j)break;
ans=max(ans,b[j]+b[loc]);
}
}
printf("%d\n",ans);
return 0;
}
标签:取模,loc,省选,tot,模数,ans,include,联考
From: https://www.cnblogs.com/BigSmall-En/p/16822770.html