Codeforces 889E - Mod Mod Mod(dp+状态设计)
题目名称 hopping
我们记 \(x_i=X\bmod a_1\bmod a_2\bmod\dots\bmod a_i\),也就是 \(X\) 连续 mod 上前 \(i\) 个数后得到的结果。
一个非常 naive 的想法是设 \(dp_{i,j}\) 表示考虑到前 \(i\) 个数,当前的 \(x_i=j\) 的最大的 \(\sum\limits_{k=1}^ix_k\),显然有一个 \(\mathcal O(na_i)\) 的转移。但事实上稍微了解一下 \(dp\) 优化的同学都可用看出这个 \(dp\) 是没有前途的,因为这个状态本身就无法优化,每个 \(dp_{i,j}\) 都有可能对最终的 \(dp_n\) 产生贡献。
于是我们只好换个状态。首先可以观察到一个性质,就是若 \(x_i\ne 0\),那么若我们令 \(X\leftarrow X-1\) 一定有新的 \(x_i\) 等于原本的 \(x_i\) 减 \(1\),我们记 \(Y=\sum\limits_{j=1}^ix_j-x_i\),根据上面的推论可知,如果我们令 \(X\leftarrow X-x_i+v(v\in[0,x_i])\) 一定有 \(\sum\limits_{j=1}^ix_j=Y+vi\)。于是我们考虑将 \([0,j]\) 搞在一起转移。设 \(dp_{i,j}\) 为考虑到前 \(i\) 个数,当前的 \(x_i=j\) 的最大的 \(Y\)。考虑怎么转移,我们考虑枚举一个 \(k\) 并将 \(X\) 改为 \(X-x_i+k\),那么就有 \(dp_{i+1,k\bmod a_{i+1}}\leftarrow dp_{i,j}+(k-k\bmod a_{i+1})\times i\)(因为将 \(X\) 改为 \(X-x_i+k\) 之后,真实的 \(\sum\limits_{j=1}^ix_j=Y+ki\),\(\sum\limits_{j=1}^ix_j-(k\bmod a_{i+1})=Y+ki-i(k\bmod a_{i+1})=dp_{i,j}+(k-k\bmod a_{i+1})\times i\)),但显然我们不可能枚举 \(k\) 进行转移,考虑将 \([0,j]\) 中所有数 \(\bmod a_{i+1}\) 的值写成一排,若 \(j\ge a_{i+1}\) 那显然是若干个 \(0...a_{i+1}-1\) 的周期加一个零头,不难发现我们最优转移点只有两个,那就是最后一个周期的 \(a_{i+1}-1\),以及最后零头部分的最后一个数(\(j\bmod a_{i+1}\)),因为其他状态要么没有这两个状态来得优,要么可以通过这两个状态在未来的转移中得到,这个稍微想想就能想通;若 \(j<a_{i+1}\),与上面的情况也类似,只不过少了最后一个周期的 \(a_{i+1}-1\) 的情况。形式化地写下来就是以下状态转移方程:
-
\(a_{i+1,j}\leftarrow dp_{i,j}(j<a_{i+1})\)
-
\(a_{i+1,j\bmod a_{i+1}}\leftarrow dp_{i,j}+(j-j\bmod a_{i+1})\times i(j\ge a_{i+1})\)
\(a_{i+1,a_{i+1}-1}\leftarrow dp_{i+j}+(\lfloor\dfrac{j+1}{a_{i+1}}\rfloor\times a_{i+1}-a_{i+1})\times i(j\ge a_{i+1})\)
第一维可以直接去掉,第二维可以用 map 优化,注意到每个 \(j\) 最多转移 \(\log a_i\) 次,因此复杂度 \(n\log a_i\log n\),可通过此题。
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,63,sizeof(a))
#define pb push_back
#define ppb pop_back
#define mp make_pair
template<typename T1,typename T2> void chkmin(T1 &x,T2 y){if(x>y) x=y;}
template<typename T1,typename T2> void chkmax(T1 &x,T2 y){if(x<y) x=y;}
typedef pair<int,int> pii;
typedef long long ll;
typedef unsigned int u32;
typedef unsigned long long u64;
namespace fastio{
#define FILE_SIZE 1<<23
char rbuf[FILE_SIZE],*p1=rbuf,*p2=rbuf,wbuf[FILE_SIZE],*p3=wbuf;
inline char getc(){return p1==p2&&(p2=(p1=rbuf)+fread(rbuf,1,FILE_SIZE,stdin),p1==p2)?-1:*p1++;}
inline void putc(char x){(*p3++=x);}
template<typename T> void read(T &x){
x=0;char c=getchar();T neg=0;
while(!isdigit(c)) neg|=!(c^'-'),c=getchar();
while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
if(neg) x=(~x)+1;
}
template<typename T> void recursive_print(T x){if(!x) return;recursive_print(x/10);putc(x%10^48);}
template<typename T> void print(T x){if(!x) putc('0');if(x<0) putc('-'),x=~x+1;recursive_print(x);}
void print_final(){fwrite(wbuf,1,p3-wbuf,stdout);}
}
const int MAXN=2e5;
int n;ll a[MAXN+5];
map<ll,ll> dp;
int main(){
scanf("%d",&n);for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
dp[a[1]-1]=0;
for(int i=1;i<n;i++){
for(map<ll,ll>::iterator it=dp.lower_bound(a[i+1]);it!=dp.end();it++){
ll x=it->fi,y=it->se;
dp[x%a[i+1]]=max(dp[x%a[i+1]],y+1ll*i*(x-x%a[i+1]));
dp[a[i+1]-1]=max(dp[a[i+1]-1],y+1ll*i*((x+1)/a[i+1]*a[i+1]-a[i+1]));
} dp.erase(dp.lower_bound(a[i+1]),dp.end());
} ll ans=0;
for(map<ll,ll>::iterator it=dp.begin();it!=dp.end();it++){
ll x=it->fi,y=it->se;chkmax(ans,y+x*n);
} printf("%lld\n",ans);
return 0;
}

浙公网安备 33010602011771号