思路
首先可以想到, x = a i − 1 x=a_i-1 x=ai−1 中肯定是存在最优解的。那么考虑 dp。
设 d p i , j dp_{i,j} dpi,j 表示第 i i i 个数, x x x 取 j j j 的最大值,分两种情况:
- j < a i j<a_i j<ai: d p i , j = d p i − 1 , j dp_{i,j}=dp_{i-1,j} dpi,j=dpi−1,j,即可以直接转移;
-
j
≥
a
i
j\ge a_i
j≥ai:分两种转移:
- 把 x x x 变为 a x − 1 a_x-1 ax−1,则 d p i , a i − 1 = d p i − 1 , j + ( i − 1 ) × ( ⌊ j + 1 a i ⌋ × a i − a i ) dp_{i,a_i-1}=dp_{i-1,j}+(i-1)\times(\lfloor\frac{j+1}{a_i}\rfloor\times a_i-a_i) dpi,ai−1=dpi−1,j+(i−1)×(⌊aij+1⌋×ai−ai);
- 就取当前的值,则 d p i , j m o d a i = d p i , j + ( i − 1 ) × ( j − j m o d a i ) dp_{i,j\bmod a_i}=dp_{i,j}+(i-1)\times(j-j\bmod a_i) dpi,jmodai=dpi,j+(i−1)×(j−jmodai)。
由于值域比较大,所以直接开个 map 来维护 d p dp dp 数组,再继续优化空间,用滚动数组的思想。时间复杂度为 O ( n log n log V ) O(n\log n\log V) O(nlognlogV)( V V V 为值域)。
代码
#include <bits/stdc++.h>
#define int long long
#define x first
#define y second
using namespace std;
const int N = 2e5+5;
int n,a[N],ans;
map<int,int> dp;
signed main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n;
for(int i = 1;i<=n;i++)
cin>>a[i];
dp[a[1]-1] = 0;
for(int i = 2;i<=n;i++)
{
for(auto j = dp.lower_bound(a[i]);j!=dp.end();dp.erase(j++))
{
int x = j->x,y = j->y;
dp[x%a[i]] = max(dp[x%a[i]],y+(i-1)*(x-x%a[i]));
dp[a[i]-1] = max(dp[a[i]-1],y+(i-1)*((x+1)/a[i]*a[i]-a[i]));
}
}
for(auto i = dp.begin();i!=dp.end();i++)
{
int x = i->x,y = i->y;
ans = max(ans,x*n+y);
}
cout<<ans;
return 0;
}