题目:​​http://codeforces.com/contest/889/problem/E​

这题真好玩。

官方题解说得很好。

想到相邻 a[ i ] 之间的段可能可以一起维护,但是不太会。

原来是表示成 i*x+k 的形式。其中 x 是具体的值,放在 DP 数组里只要记录 “ x<= ... 的 x 都满足这个式子” 就行,因为每次经过一个 i ,范围都是保留最底部的一些之类的。

然后写了一个不行的代码。


CF889 E Mod Mod Mod——DP_#defineCF889 E Mod Mod Mod——DP_#define_02


#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;
}

View Code

不能遍历 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;
}