CF889E Mod Mod Mod
看到这题的第一眼想法:哇这不是从\(n\)倒过来维护一些区间的右端点每次增加\(O(1)\)个区间,平移若干区间,得到\(O(n)\)个取值点,然后对于每个点二分出第一个能模的位置,暴力做得到\(O(n\log n\log A)\)的优秀复杂度吗?
哎等下,这东西好像要写个平衡树写个st表有点难写的亚子?
然后你发现他们写的都是不到1k的东西,因此肯定不用这么麻烦。
我们考虑正着维护,到了第\(i\)个数模完之后,考虑维护一整段的答案,如果当前的是\([0,x]\),则每个点拥有共同的初始值\(b\)与斜率\(i\),点则是他们自己。那么一定是取\(x\)最优。
然后这时候\(\bmod a_i\),则模完之后有效的是两段:\([0,a_i-1]\)与\([0,x\bmod a_i]\),新拆出来的段的初始值只需要加上询问点变化的差即可。容易发现这样每个数会模\(O(\log A)\)次,用map存状态,总复杂度\(O(n\log n\log A)\)。
code:
#include<bits/stdc++.h>
#define I inline
#define ll long long
#define db double
#define lb long db
#define N (200000+5)
#define M ((N<<1)+5)
#define K (700+5)
#define mod 1000000007
#define Mod (mod-1)
#define eps (1e-5)
#define ull unsigned ll
#define it iterator
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((k+1)*(x)+(y))
#define R(n) (1ll*rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using namespace std;const ll INF=1e18;map<ll,ll> f;
int n,m,k;ll x,ToT;
int main(){
freopen("1.in","r",stdin);
int i,j;scanf("%d%lld",&n,&x);f[x-1]=0;for(i=2;i<=n;i++){
scanf("%lld",&x);ll Ts=-1e18;while(!f.empty()){
auto j=*--f.end();if(j.first<x){Ts>=0&&(f[x-1]=max(f[x-1],Ts));break;}Ts=max(j.second+(i-1)*(j.first/x*x-x),Ts);
f[j.first%x]=max(f[j.first%x],j.second+(j.first-j.first%x)*(i-1));f.erase(--f.end());
}
} for(auto i:f) ToT=max(ToT,i.second+i.first*n);printf("%lld\n",ToT);
}