很水的一道黑
传送门
题目大意
给出 \(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;
}
那么多随机算法标签结果只有数据是随机的
浙公网安备 33010602011771号