【CF889E】Mod Mod Mod(DP)
阿新 • • 發佈:2021-07-18
給定一個長度為$n$的陣列$a_{1\sim n}$,定義$f(i,x)=\begin{cases}x\%a_i+f(i+1,x\%a_i)&(i < n)\\x\%a_n&(i=n)\end{cases}$。對所有正整數$x$,求$f(1,x)$的最大值。
表示模\(a_i\)餘\(1\sim Mx\)的數一種可能的貢獻,並把\(Mx\)稱作一個關鍵點。
的貢獻,得到:
\[f_{i,x\%a_i}=f_{i-1,x}+(i-1)\times(x-x\%a_i)\\
f_{i,a_i-1}=f_{i-1,x}+(i-1)\times(\lfloor\frac{x-(a_i-1)}{a_i}\rfloor\times a_i)
\]
- 給定一個長度為\(n\)的陣列\(a_{1\sim n}\),定義\(f(i,x)=\begin{cases}x\%a_i+f(i+1,x\%a_i)&(i<n)\\x\%a_n&(i=n)\end{cases}\)。
- 對所有正整數\(x\),求\(f(1,x)\)的最大值。
- \(n\le2\times10^5,a_i\le10^{13}\)
尋找關鍵點
容易發現,如果\(x\)在模過\(a_{1\sim i}\)之後不為\(0\),那麼\(x-1\)在模\(a_{1\sim i}\)的過程中始終恰好比\(x\)小\(1\)。
也就是說,我們可以寫出一個函式\(i\times x+b\)
那麼每\(DP\)到一個位置\(i\),原本的關鍵點依然是關鍵點(可能要經過取模),而\(a_{i}-1\)則成為了一個新的關鍵點。
又由於一個數取模一次至少會減半,一個關鍵點最多取模\(O(logV)\)次,所以即便我們每次列舉關鍵點暴力取模,總共也只會有\(O(nlogV)\)次操作。
動態規劃
設\(f_{i,x}\)表示當前\(DP\)到第\(i\)位,對於關鍵點\(x\),函式\(i\times x+b\)中\(b\)的最大值。
轉移只需找出大於等於\(a_i\)的那些關鍵點,分別考慮它們取模後的變化以及對新關鍵點\(a_{i}-1\)
本題中可以使用\(map\)優化。
程式碼:\(O(nlognlogV)\)
敗得義無反顧,弱得一無是處#include<bits/stdc++.h> #define Tp template<typename Ty> #define Ts template<typename Ty,typename... Ar> #define Rg register #define RI Rg int #define Cn const #define CI Cn int& #define I inline #define W while #define N 200000 #define LL long long using namespace std; int n;LL a[N+5];map<LL,LL> P;map<LL,LL>::iterator it; int main() { RI i;for(scanf("%d",&n),i=1;i<=n;++i) scanf("%lld",a+i); for(P[a[1]-1]=0,i=2;i<=n;++i) for(it=P.lower_bound(a[i]);it!=P.end();P.erase(it++))//列舉大於等於a[i]的關鍵點 P[it->first%a[i]]=max(P[it->first%a[i]],it->second+(i-1)*(it->first-it->first%a[i])),//考慮取模後的變化 P[a[i]-1]=max(P[a[i]-1],it->second+(i-1)*((it->first-(a[i]-1))/a[i]*a[i]));//考慮對新關鍵點a[i]-1的貢獻 LL t=0;for(it=P.begin();it!=P.end();++it) t=max(t,n*it->first+it->second);return printf("%lld\n",t),0;//列舉所有關鍵點統計最終答案 }