CF1801F Another n-dimensional chocolate bar 题解

本文迁移自洛谷原文

考虑到最多只会有一个

  • 没有任何一个

那么我们可以考虑类似 meet-in-the-middle 的做法。

表示考虑了前 个数,此时乘积为 的最大值, 的定义类似,不过是从 开始倒着的。dp 的时候枚举 ,枚举 ,再枚举满足 第二维大小的所有 即可。

则我们这种情况下的最好答案就是枚举一个中间断点 ,和 左边的部分的乘积 的最小值了。

此时我们需要证明,在所有选择的 的情况下, 的第二维都只要开到 即可。

不妨设一个 ,初始为 最大的位置,令 左边所有 的乘积, 右边所有 的乘积。

我们贪心的考虑,如果 ,就让 ;如果 ,就让 。在移动 的同时维护 的值。

此时第二维就需要开到一个 的大小。因为 级别的,所以 ,故第二维只需要开到 即可。因为 ,所以 ,得证。

综上,该部分复杂度为

  • 存在恰好一个

那么我们可以直接枚举这个 ,发现 左侧和右侧 的乘积均 。令 表示现暂时不选 ,其他所有位置都选之后乘积为 时的最大值。这个可以利用 快速处理。

然后我们枚举除了 的所有 的乘积 ,推出 的值最小是多少,计算出 即第 个数的贡献,乘上 即可。

该部分复杂度为

综上,总复杂度为 ,可以不知道为什么但只跑了 1.5s 通过此题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include<bits/stdc++.h>
using namespace std;
const int B=177830;
const int B2=6600;
int n,w,a[103];
double f[103][B+3],g[103][B+3],ans;
vector<int>v;
double h[B2+3];
int main(){
cin>>n>>w;
for(int i=1;i<=n;i++)
cin>>a[i];
f[0][1]=1;
for(int i=1;i<=n;i++){
for(int j=1;j<=B;j++)
for(int k=1;k<=B/j;k++)
f[i][j*k]=max(f[i][j*k],f[i-1][j]*(1.0*(a[i]/k)/a[i]));
for(int j=B;j>0;j--)
f[i][j]=max(f[i][j],f[i][j+1]);
}
g[n+1][1]=1;
for(int i=n;i;i--){
for(int j=1;j<=B;j++)
for(int k=1;j*k<=B;k++)
g[i][j*k]=max(g[i][j*k],g[i+1][j]*(1.0*(a[i]/k))/a[i]);
for(int j=B;j>0;j--)
g[i][j]=max(g[i][j],g[i][j+1]);
}
for(int i=0;i<=n;++i)for(int j=1;j<=B;++j)
if((w+j-1)/j<=B)ans=max(ans,f[i][j]*g[i+1][(w+j-1)/j]);
for(int i=1;i<=n;++i){
if(1){
for(int j=1;j<=B2;++j)h[j]=0;
for(int j=1;j<=B2;++j)
for(int k=1;k*j<=B2;++k)
h[j*k]=max(h[j*k],f[i-1][j]*g[i+1][k]);
for(int j=B2;j;--j)h[j]=max(h[j],h[j+1]);
for(int j=1;j<=B2;++j){
int ee=(w+j-1)/j;ee=max(ee,1);
if(ee>a[i])continue;
int e2=a[i]/ee;
ans=max(ans,1.0*e2/(1.0*a[i])*h[j]);
}
}
}
cout<<fixed<<setprecision(15)<<ans*w<<'\n';
}