正题
CF889E
luogu
题目大意
给你 n 个数,让你选择一个X,使得 ∑i=1nXmoda1moda2...modai\sum_{i=1}^nX\mod a_1\mod a_2...\mod a_i∑i=1nXmoda1moda2...modai 最大
解题思路
可以发现必定存在一个 i ,使得当前点贡献为 aia_iai,否则把 X 加一显然可以得到更优的答案
朴素的状态转移很难优化,考虑令 fi,jf_{i,j}fi,j 表示到第 i 个点,当前值为 0∼j0\sim j0∼j,当前总贡献为 i×(0∼j)+fi,ji\times (0\sim j)+f_{i,j}i×(0∼j)+fi,j,即把 j 个状态存到了一起,然后把模后的贡献存在 f 中
对于 ai+1>ja_{i+1}>jai+1>j,直接传递即可
否则存在两种转移
fi+1,jmodai+1=max(fi,j+i×(j−jmodai+1)fi+1,ai+1−1=max(fi,j+i×(((j+1)/ai+1×ai+1−1)−(ai+1−1))f_{i+1,j\mod a_{i+1}}=max(f_{i,j}+i\times (j-j\mod a_{i+1}) \\ f_{i+1,a_{i+1}-1}=max(f_{i,j}+i\times(((j+1)/a_{i+1}\times a_{i+1}-1)-(a_{i+1}-1)) fi+1,jmodai+1=max(fi,j+i×(j−jmodai+1)fi+1,ai+1−1=max(fi,j+i×(((j+1)/ai+1×ai+1−1)−(ai+1−1))
第二个转移即找到最大的值使其转移到 ai+1−1a_{i+1}-1ai+1−1
因为一个数模了之后至少减半,所以最多转移 logxlog\ xlog x次
时间复杂度 O(nlognlogx)O(nlog\ n\ log\ x)O(nlog n log x)
code
#include<map>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
map<ll,ll>::iterator it;
ll n,x,y,z,ans;
map<ll,ll>f;
int main()
{scanf("%lld",&n);for(int i=1;i<=n;++i){scanf("%lld",&x);if(i==1)f[x-1]=0;else{for(it=f.lower_bound(x);it!=f.end();f.erase(it++)){y=(*it).first;z=(*it).second;f[y%x]=max(f[y%x],z+(i-1)*(y-y%x));f[x-1]=max(f[x-1],z+(i-1)*((y+1)/x*x-x));}}}for(it=f.begin();it!=f.end();it++)ans=max(ans,(*it).first*n+(*it).second);printf("%lld",ans);return 0;
}