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;
}
posted @ 2021-09-02 16:22  shrtcl  阅读(90)  评论(0)    收藏  举报