[省选联考 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;
}
posted @ 2021-10-17 11:20  comld  阅读(181)  评论(0编辑  收藏  举报