很水的一道黑

传送门

题目大意

给出 \(n\) 个元素,每个元素有两个权值 \(a_i\)\(b_i\),从中选出若干元素,令取出元素的 \(a_i\) 之和为 \(S_a\),其余元素的 \(b_i\) 之和为 \(S_b\),最大化 \(S_a\times{S_b}\)

分析

\(a_i\)\(b_i\) 的值分别在 \([1,A]\)\([1,B]\) 间均匀随机生成,所以 \(a_i\)\(b_i\) 之和相差并不大,贪心选更大的 \(S_a\)\(S_b\) 即可得出最优解。

可以按 \(\frac{a_i}{b_i}\) 排好序后在中点附近枚举断点,差不多枚举 \(100\) 个即可。

最后断点左边都选 \(b_i\),右边都选 \(a_i\),得出的结果取 max,记得开 int_128。

优化

但是当 \(a_i\)\(b_i\) 本身相差很小甚至相等时,按如上方法求解很容易举出反例。

所以每个断点附近还要进行几次暴搜来保证正确性(实测搜 \(10\) 个即可)。

代码

#include <bits/stdc++.h>
#define cys __int128
using namespace std;
const int maxn=3009;
int T,n;
long long A,B;
cys ans,l,r;
struct node{
	cys a,b;
}s[maxn];
inline cys read(){
	cys res=0;char c=getchar();
	for(;c<'0'||c>'9';c=getchar());
	for(;c>='0'&&c<='9';c=getchar()) res=(res<<3)+(res<<1)+(c^48);
	return res;
}
void write(cys x){
	if(x>9) write(x/10);
	putchar(x%10+'0');
}
bool cmp(node x,node y){return 1.0*x.a/x.b>1.0*y.a/y.b;}
cys dfs(int step,cys X,cys Y){
	if(step==r+1) return X*Y;
	return max(dfs(step+1,X+s[step].a,Y),dfs(step+1,X,Y+s[step].b));
}
int main(){
	scanf("%d%d%lld%lld",&T,&n,&A,&B);
	while(T--){
		for(int i=1;i<=n;i++) s[i].a=read(),s[i].b=read();
		sort(s+1,s+n+1,cmp);ans=0;
		for(int k=max(1,n/2-50);k<=min(n,n/2+50);k++){
			cys x=0,y=0;
			l=max(1,k-5),r=min(n,k+5);
			for(int i=1;i<l;i++) x+=s[i].a;
			for(int i=r+1;i<=n;i++) y+=s[i].b;
			ans=max(ans,dfs(l,x,y));
		}
		write(ans),puts("");
	}
	return 0;
}

那么多随机算法标签结果只有数据是随机的