[省选联考 2021 B 卷] 取模

题目链接

[P7521 省选联考 2021 B 卷] 取模 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题解

想了半天一看竟然是个暴力题。。。

我们可以把所有的情况分为两类:(a_i+a_j< a_k)(a_i+a_jgeq 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}),那么就有(ansgeq a_i+a_{i+1}-a_{i+2})(a_{i+2}-ansgeq 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;
}
原文地址:https://www.cnblogs.com/ZH-comld/p/15416470.html