CF889E Mod Mod Mod

CF889E Mod Mod Mod 

%ywy

一种把状态减少,只保留有效状态的DP

但是一个地方不太明白

首先,只和当前mod ai的值有关系,朴素的设法是:dp[i][j],%ai=j的最总和是多少。

然而实在不方便转移

而注意到,xi一定是单调不升的,所以i位置是xi,那么ans可以表示为xi*i+b的形式。只用保留b即可

神仙的状态设计:dp[i][j]表示,第i位的x为j时,所谓的b最大是dp[i][j]

显然也具有最优子结构的性质

考虑转移,i->i+1:思想:值域过大,尽量减少不必要的转移以减少状态数

枚举j,用dp[i][j]更新

首先发现,当j<a[i+1]时候,dp[i+1][j]=dp[i][j]

否则,考虑用dp[i][j]来给[0,j]一起做转移,把这些dp[i][k]的dp都看做dp[i][j],(正确性存疑,感觉可能dp[i][k]更小但是转移大了?)

从k=j,k越来越小的时候,取模后也会越来越小,这些转移过去都没有意义。(应该不能说是没意义,而是dp[]其实是同一个值!)

但是会mod到下一个循环节。也即k%a(i+1)=a(i+1)-1

对于y,<=j的最后一个%a(i+1)=a(i+1)-1的位置,这个可以是有意义的(dp[]不同了)

那么,对于比y还小的k,--k,取模之后也会越来越小,其实也没意义了。(dp[i][k]都和dp[i][y]相同)

每个数只会mod logn次

 总复杂度也是O(nlognlogx)

懵了懵了不管了。

#include<bits/stdc++.h>
#define reg register int
#define il inline
#define fi first
#define se second
#define mk(a,b) make_pair(a,b)
#define numb (ch^'0')
#define pb push_back
#define solid const auto &
#define enter cout<<endl
#define pii pair<int,int>
using namespace std;
typedef long long ll;
template<class T>il void rd(T &x){
    char ch;x=0;bool fl=false;while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
    for(x=numb;isdigit(ch=getchar());x=x*10+numb);(fl==true)&&(x=-x);}
template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');}
template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');}
template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('\n');}
namespace Modulo{
const int mod=998244353;
int ad(int x,int y){return (x+y)>=mod?x+y-mod:x+y;}
void inc(int &x,int y){x=ad(x,y);}
int mul(int x,int y){return (ll)x*y%mod;}
void inc2(int &x,int y){x=mul(x,y);}
int qm(int x,int y=mod-2){int ret=1;while(y){if(y&1) ret=mul(x,ret);x=mul(x,x);y>>=1;}return ret;}
}
//using namespace Modulo;
namespace Miracle{
const int N=200000+5;
int n;
ll a[N];
map<ll,ll,greater<ll> >mp;
ll tmp[5*N];
int main(){
    rd(n);
    for(reg i=1;i<=n;++i) rd(a[i]);
    mp[a[1]-1]=0;
    for(reg i=1;i<n;++i){
        int ptr=0;
        for(solid x:mp){
            if(x.fi<a[i+1]) break;
            mp[a[i+1]-1]=max(mp[a[i+1]-1],mp[x.fi]+(ll)i*a[i+1]*((x.fi-a[i+1]+1)/a[i+1]));
            mp[x.fi%a[i+1]]=max(mp[x.fi%a[i+1]],mp[x.fi]+(ll)i*(x.fi-x.fi%a[i+1]));
            tmp[++ptr]=x.fi;
        }
        while(ptr) mp.erase(tmp[ptr--]);
    }
    ll ans=0;
    for(solid x:mp){
        ans=max(ans,(ll)x.fi*n+x.se);
    }
    ot(ans);
    return 0;
}

}
signed main(){
    Miracle::main();
    return 0;
}

/*
   Author: *Miracle*
*/
View Code

同样的状态减少转移,有点类似整体DP

把[0,j]的dp都看成dp[i][j]取max就覆盖了

猜你喜欢

转载自www.cnblogs.com/Miracevin/p/10965865.html
mod