[省选联考 2021 B 卷] 取模
题目链接
[P7521 省选联考 2021 B 卷] 取模 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
题解
想了半天一看竟然是个暴力题。。。
我们可以把所有的情况分为两类:\(a_i+a_j< a_k\)和\(a_i+a_j\geq a_k\)
对于第二种情况,可以证明只能从\((a_{i-2}+a_{i-1})\%a_i\)中取得,如果有一个\(a_p\%a_i>a_{i-1}\)所以就有\(a_i+a_{i-1}<a_p\)所以我们选取后面的更优。
那么对于第一种情况,暴力的做法是枚举每个模数,把所有数取模后的值排序后双指针。
那么我们从大到小枚举模数,可以证明做的次数是\(log\)的。
假设有\(ans<a_x<a_{x+1}<a_{x+2}<...<a_{n}\),那么就有\(ans\geq a_i+a_{i+1}-a_{i+2}\)即\(a_{i+2}-ans\geq a_i-ans+a_{i+1}-ans\)
所以最多会有\(Log\)个。
代码
#include<bits/stdc++.h>
#define N 200009
using namespace std;
typedef long long ll;
const int maxn=500000;
int a[N],n,b[N];
inline ll rd(){
ll x=0;char c=getchar();bool f=0;
while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return f?-x:x;
}
int main(){
n=rd();
for(int i=1;i<=n;++i){
a[i]=rd();
}
sort(a+1,a+n+1);
int ans=0;
for(int i=3;i<=n;++i)ans=max(ans,(a[i-2]+a[i-1])%a[i]);
for(int i=n;i>=1;--i)if(a[i]-1>ans){
int tot=0;
for(int j=1;j<=n;++j){
if(j!=i)b[++tot]=a[j]%a[i];
}
sort(b+1,b+tot+1);
int p=0;
for(int j=tot;j>=1;--j){
while(p+1<j&&b[p+1]+b[j]<a[i])p++;
if(p<j&&p)ans=max(ans,b[p]+b[j]);
}
}
cout<<ans;
return 0;
}