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

 

posted on 2019-06-13 10:42  Narh  阅读(350)  评论(0编辑  收藏  举报

导航