Wooden_Raft問題解決
ポータル
試験は、試験はちょうど、他のトピックをする時間を持っていない、ハード出てきません、私の死に病気。
:これは一般的な慣行の2つだけの事で物事を行う非常に悪いです
1.貪欲ファック。
2.一次元を固定しました。
列挙は、当然の列挙はしない一次元Yに従事し、その後木材部は、x yに変更した選択
まず、我々は> = Y木材Yが構成何決定することができ、
その後、セットX \ [KY、に(\を KY + Y)\) 、我々は、xの長さに切断され> = KY木材を選択することができ、
我々は、貪欲場合のように、Y%NATURALが最大から選択される、Yの選択を妨害しません。
私たちは)2 X 2つの状況をy少し干渉のために、なぜ?ナンセンス:(なく、できるだけ大きなX、ではない/わずかなX-まあを切ることができるカットの下に議論する
内部木片から1二つのX(おそらく発生特にロングウッド)を切断
範囲X内の二つの長い二つの異なる断面木材から2を
二つの異なる2つの短縮範囲から3.木材最長Z×(木材\([KY、KY + Y )\) 他の内側、\([KY + Y、\
inftyの)\) の時間複雑度\(O(\ sum_ {i = 1} ^ {MAXX } MAXX / I)= O(MAXXログMAXX)\)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=5e5+6;
int n,t,ky,val,maxx=-1,pre_num,num[N],v[N],pre[N];
ll ans,k,sum=0;
inline int read(){
int T=0,F=1; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') F=-1; ch=getchar();}
while(ch>='0'&&ch<='9') T=(T<<3)+(T<<1)+(ch-48),ch=getchar();
return F*T;
}
struct Pair{
int mod,w;
Pair(int x=-1,int y=-1){mod=x,w=y;}
bool operator < (const Pair &a) const {return mod!=a.mod?mod<a.mod:w<a.w;}
};
struct xx{
Pair x,y;
void update(Pair z){y=max(y,min(x,z)),x=max(x,z);}
};
void Max(ll p,ll q){ans=max(ans,(p<2ll?0ll:p*q));}
int main(){
n=read();
for(int i=1;i<=n;++i) t=read(),++v[t],maxx=max(maxx,t);
for(int i=maxx;i>=0;--i) num[i]=num[i+1]+v[i];
t=0;
for(int i=0;i<=maxx;++i){
if(v[i]) t=i;
pre[i]=t;
}
for(int y=2;y<=maxx;++y){
sum=0,ky=maxx+1; xx tmp;
for(int i=y;i<=maxx;i+=y) sum+=num[i];//截得出sum根y
for(int i=maxx/y;i>=0;--i){
val=pre[ky-1],pre_num=(tmp.x.mod>=0)+(tmp.y.mod>=0),t=i*y;
//val:目前范围中的最大值
if(val>=t){
tmp.update((Pair){val%y,val});
if(v[val]==1) val=pre[val-1];
if(val>=t) tmp.update((Pair){val%y,val});
}//更新最大值,次大值
if(tmp.x.mod>=0) Max(min((ll)(t+tmp.x.mod)>>1,sum-i),y);
//从一根木头里截
if(tmp.y.mod>=0){
Max(min((ll)t+tmp.y.mod,sum-i-i),y);
//两根木头里截次长
if(pre_num+(tmp.x.w<ky)>1) Max(min((ll)t+tmp.x.mod,sum-i-i-1),y);
//两根木头里最次长
}
ky=t;
}
}
printf("%lld\n",ans);
return 0;
}