CF1223G Wooden Raft 题解
题意
有 \(n\) 个木条,长为 \(a_i\) 。你可以分割木条(分割后仍需整数长度),之后你需要选出 \(2\) 根长为 \(x\) 的木条,和 \(x\) 根长为 \(y\) 的木条,使 \(x\times y\) 最大。 \((x,y\ge 2)\)
\((1\le n,a_i\le 5\times10^5)\)
题解
考虑枚举 \(y\) ,只需要在剩下的木条中选出两个 \(x\) ,比较好做。
此时最多可能选出 \(\text{cnt}=\sum_{i=1}^{n}\lfloor\frac{a_i}{y}\rfloor\) 个木条。
接下来考虑两种情况:
- 两个 \(x\) 在同一个木条中:
有可能会占用 \(y\) 最多的个数,所以当占用 \(y\) 个数相同的时候希望能让 \(2x\bmod y\) 尽量大。
自 然 想到设 \(2x\in[ky,ky+y)\) ,容易计算出此处 \(2x\bmod y\) 最大值 \(\text{mx}=\max_{a_i\ge ky}\left\{a_i\bmod y\right\}\)
此时 \(x\) 能够取到 \(\min(\text{cnt}-k,\lfloor\frac{\text{mx}}{2}\rfloor)\) 。
实现的时候从大到小枚举 \(k\) 比较方便,时间复杂度 \(O(\frac{\max\left\{a_i\right\}}{y})\) 。
- 两个 \(x\) 不在同一个木条中
和上面思路一样,设 \(x\in[ky,ky+y]\) ,仍从大到小枚举 \(k\) 。
显然取 \(x\bmod y\) 最大值 \(\text{mx1}\) 很优,不过次大值 \(\text{mx2}\) 所属木条就会被多占用一个 \(k\) (此时需要注意这个木条是否够长,长度够 \(ky+\text{mx1}\) )。
如果取 \(\text{mx2}\) 就不需要这个额外的 \(k\) 了。
这时 \(x\) 可以取到 \(\max(\min(\text{cnt}-2k,ky+\text{mx2}),\min(\text{cnt}-2k-1,ky+\text{mx1}))\) 。(前提满足上面条件)
总时间复杂度 \(O(n\ln n)\) 。
非常难写……
#include <bits/stdc++.h>
using namespace std;
const int N=1e6+5;
typedef long long ll;
int n,m,a[N],l[N];
ll ans;
void chk(ll x,int y) {if(x>1) ans=max(ans,x*y);}
signed main(){
scanf("%d",&n);l[0]=-1;
while(n--) {int x;scanf("%d",&x);a[x]++;m=max(m,x);}
for(int i=1;i<=m*2;i++){
if(a[i]) l[i]=i;else l[i]=l[i-1];
a[i]+=a[i-1];
}
for(int y=2;y<=m;y++){
ll cnt=0;
for(int i=y-1;i<=m;i+=y) cnt+=(i/y+1)*(a[i+y]-a[i]);
for(int i=m,j=(m/y)*y,mx1=-1,mx2=-1;~i;i=j-1,j-=y){
int t1=l[i],t2=(a[l[i]]-a[l[i]-1]>1)?l[i]:(l[i]<0?-1:l[l[i]-1]),k=j/y,fl=1;
if(t1>=j){
t1%=y;
if((~mx1)&&((~mx2)||(t1%y>=mx1))) chk(min(cnt-k*2-1,(ll)j+max(t1%y,mx1)),y);
if(t1>mx1) mx2=mx1,mx1=t1;else if(t1>mx2) mx2=t1,fl=0;
if(t2>=j) mx2=max(mx2,t2%y);
}
if(~mx1){
chk(min(cnt-k,(ll)(j+mx1)/2),y);
if(~mx2) chk(min(cnt-k*2,(ll)j+mx2),y);
}
}
}
printf("%lld\n",ans);
return 0;
}

浙公网安备 33010602011771号