CF889 E Mod Mod Mod——DP
题目:http://codeforces.com/contest/889/problem/E
这题真好玩。
官方题解说得很好。
想到相邻 a[ i ] 之间的段可能可以一起维护,但是不太会。
原来是表示成 i*x+k 的形式。其中 x 是具体的值,放在 DP 数组里只要记录 “ x<= ... 的 x 都满足这个式子” 就行,因为每次经过一个 i ,范围都是保留最底部的一些之类的。
然后写了一个不行的代码。
#include<cstdio> #include<cstring> #include<algorithm> #include<map> #define ll long long using namespace std; ll rdn() { ll ret=0;bool fx=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();} while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar(); return fx?ret:-ret; } ll Mx(ll a,ll b){return a>b?a:b;} const int N=2e5+5,M=N*20; int n,tot,l[N],r[N];ll a[N],dp[M],dy[M],ans; map<ll,int> mp[N]; int main() { n=rdn(); for(int i=1;i<=n;i++)a[i]=rdn(); r[1]=++tot; dp[tot]=0; dy[tot]=a[1]-1; for(int i=1;i<n;i++) { l[i+1]=r[i]=tot; for(int j=l[i]+1,d;j<=r[i];j++) { ll k=dp[j],r=dy[j],tp=r%a[i+1]; if(r>=a[i+1]) { if(!mp[i+1].count(a[i+1]-1)) { mp[i+1][a[i+1]-1]=++tot; dy[tot]=a[i+1]-1; } d=mp[i+1][a[i+1]-1]; dp[d]=Mx(dp[d],k+i*(r-tp-a[i+1])); } if(!mp[i+1].count(tp)) { mp[i+1][tp]=++tot; dy[tot]=tp; } d=mp[i+1][tp]; dp[d]=Mx(dp[d],k+i*(r-tp)); } } for(int i=l[n]+1;i<=tot;i++) { ll k=dp[i],r=dy[i]; ans=Mx(ans,n*r+k); } printf("%lld\n",ans); return 0; }
不能遍历 r 没有变的位置。也不能让它们占用更多空间,比如在 i 处用一个位置、又在 i+1 处用一个位置。
然后抄了一番题解。原来 map 可以这样遍历。
#include<cstdio> #include<cstring> #include<algorithm> #include<map> #define ll long long using namespace std; ll rdn() { ll ret=0;bool fx=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();} while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar(); return fx?ret:-ret; } ll Mx(ll a,ll b){return a>b?a:b;} const int N=2e5+5; int n;ll a[N],ans; map<ll,ll> mp; map<ll,ll>::iterator it; int main() { n=rdn();for(int i=1;i<=n;i++)a[i]=rdn(); mp[a[1]-1]=0; for(int i=1;i<n;i++) { while(1) { it=mp.end(); it--; ll r=(*it).first, k=(*it).second; if(r<a[i+1])break; mp.erase(it); mp[a[i+1]-1]=Mx(mp[a[i+1]-1],k+i*(r-r%a[i+1]-a[i+1])); mp[r%a[i+1]]=Mx(mp[r%a[i+1]],k+i*(r-r%a[i+1])); } } for(it=mp.begin();it!=mp.end();it++) ans=Mx(ans,n*(*it).first+(*it).second); printf("%lld\n",ans); return 0; }