非常native的题目,我们考虑以下一些性质:
.一个数若mo了一个小于自己的模数,那么其至少变成原来的一半。
我们构造三元对(i,j,k)表示当前做到i位,当前x可以取0至j,当前的答案是k+i*j,
我们考虑这样的转移:
(i,j,k)to (i+1,j%num[i+1],k+i*(j-j%num[i+1]))
(i,j,k) to (i+1,num[i+1]-1,k+i*(j-j%num[i+1]-num[i+1])),
我们考虑dp:f[i][j]中计录max k,那么就有O(N^2)个状态,
我们发现比其小的状态转移后k可以最后统计,那么我们只要修改比其大的即可。
由前文性质得每个数最多log次修改,我们用map维护即可。
下文代码在C++11及更高环境下才能通过(auto 是C++11的保留字&&C++17除外,这玩意超级玄学)
#include<bits/stdc++.h> #define LL long long #define fi first #define se second using namespace std; map<LL,LL> mp; LL ans,A,B,nex; LL n,a[1000007]; int main () { scanf("%lld",&n); for (int i=1;i<=n;i++) scanf("%lld",a+i); mp[(LL)a[1]-1]=0; for (int i=1;i<=n;i++) { while (1) { auto it=mp.lower_bound(a[i]); if (it==mp.end()||it->fi<a[i]) break; A=it->fi,B=it->se; mp.erase(it); nex=A%a[i]; mp[nex]=max(mp[nex],B+(i-1)*(A-A%a[i])); mp[a[i]-1]=max(mp[a[i]-1],B+(i-1)*(A-A%a[i]-a[i])); } } for (auto i:mp) ans=max(ans,i.fi*n+i.se); printf("%lld ",ans); }