CF889E 不知道是不是新做法

· · 个人记录

Solution

显然我们只保留 a 的前缀 min,然后把每个位置挂在他前面第一个前缀 min 是。大概这样:

然后记第 i 个前缀 min 的值是 b_i。记前缀 min 的个数是 m。记前 k 个前缀 min 包含了 pre_k 个元素。

我们设计这样一个 DP:dp_i 表示,将前 ib 全部改成 b_i,能获得的最大答案。

考虑 $dp_i$ 转移。记 $X \bmod b_i = x_1$,$x_1 \bmod b_{i+1} = x_2$。 那么显然 $x_1 = x_2 + k \times b_{i+1}$,$k$ 是一个自然数。 假设我们知道 $x_2$,一定会让 $x_1$ 尽量大。 发现:$x_2 \le b_i \bmod b_{i+1}$ 时,$x_1 = x_2 + \lfloor \frac{b_i}{b_{i+1}} \rfloor b_{i+1}$;否则,$x_1 = x_2 + (\lfloor \frac{b_i}{b_{i+1}} \rfloor-1) b_{i+1}$。 如果我们选的是后者,那么相当于转移到 $dp_{i+1}$,但是多了 $pre_{i} \times (\lfloor \frac{b_i}{b_{i+1}} \rfloor-1) b_{i+1}$,也就是 $$ dp_i \leftarrow dp_{i+1} + pre_{i} \times (\lfloor \frac{b_i}{b_{i+1}} \rfloor-1) b_{i+1} $$ 如果选的是前者,即 $x_2 \le b_i \bmod b_{i+1}$。那我们找到第一个 $b_j$ 使得 $b_j < b_i \bmod b_{i+1}$。容易知道在 $(i,j)$ 中的 $b$ 都是没有用的。再分析下一次取模的结果和 $(b_i \bmod b_{i+1}) \bmod b_j$ 的大小关系。可以直接从 $dp_j$ 转移,也可以再拿到 $(b_i \bmod b_{i+1}) \bmod b_j$ 往后继续转移。 每取模一次会减半,所以我们只会进行 $O(\log V)$ 次操作。故复杂度为 $O(n \log V \log n)$。 ```cpp #include<bits/stdc++.h> #define int long long #define ffor(i,a,b) for(int i=(a);i<=(b);i++) #define roff(i,a,b) for(int i=(a);i>=(b);i--) using namespace std; const int MAXN=2e5+10; int n,m,a[MAXN],len[MAXN],mod[MAXN],pos[MAXN],pre[MAXN],dp[MAXN]; int bfind(int l,int r,int v) { int ans=r+1; while(l<=r) { int mid=(l+r>>1); if(mod[mid]<v) ans=mid,r=mid-1; else l=mid+1; } return ans; } signed main() { // freopen("ternarysearch.in","r",stdin); // freopen("ternarysearch.out","w",stdout); ios::sync_with_stdio(false),cin.tie(0),cout.tie(0); cin>>n; ffor(i,1,n) cin>>a[i]; int lst=LONG_LONG_MAX; ffor(i,1,n) if(a[i]<lst) ++m,pos[m]=i,mod[m]=a[i],lst=a[i]; lst=n+1; roff(i,m,1) len[i]=lst-pos[i],lst=pos[i]; ffor(i,1,m) pre[i]=pre[i-1]+len[i]; dp[m]=(mod[m]-1)*n; roff(i,m-1,1) { dp[i]=pre[i]*((mod[i]/mod[i+1])-1)*mod[i+1]+dp[i+1]; int ex=pre[i]*(mod[i]/mod[i+1]*mod[i+1]),MOD=mod[i]%mod[i+1]; while(1) { int pos=bfind(1,m,MOD); if(pos==m+1) {dp[i]=max(dp[i],ex+(MOD-1)*n);break ;} dp[i]=max(dp[i],ex+((MOD/mod[pos]-1)*mod[pos])*pre[pos-1]+dp[pos]); ex+=MOD/mod[pos]*mod[pos]*pre[pos-1]; MOD%=mod[pos]; } } cout<<dp[1]; return 0; } ```