[ DP ] Codeforces889E Mod Mod Mod

xi=xi1 mod ai(x>1),x1=x x i = x i − 1   m o d   a i ( x > 1 ) , x 1 = x ,即 x x 依次对前 i 个数取模后的值。
ansi=f(x,1)f(xii+1) a n s i = f ( x , 1 ) − f ( x i , i + 1 ) ,即前 i i xi 的和。那么答案就是最大的 ansn a n s n
枚举 ai a i ,由于 xi x i 是递减的,一个状态可以表示成二元组 (mx,s) ( m x , s ) ,表示 xi x i 的范围是 [0,mx] [ 0 , m x ] , ansi=ixi+s a n s i = i x i + s
初始时的状态是 (a11,0) ( a 1 − 1 , 0 )
2 2 种转移:

-转移后的 mx<ai+11 ,也就是尽量多地取 xi x i 。转移到 (r mod ai+1,s+i(rr mod ai+1)) ( r   m o d   a i + 1 , s + i ( r − r   m o d   a i + 1 ) )
- 转移前的 mxai+11 m x ≥ a i + 1 − 1 ,转移后的 mxai+11 m x ≥ a i + 1 − 1 ,也就是使 xi+1 x i + 1 可以任意取。转移到 (ai+11,s+i(rr mod ai+1ai+1))) ( a i + 1 − 1 , s + i ( r − r   m o d   a i + 1 − a i + 1 ) ) )

第二种转移只用记最大值就好了。
然后算下复杂度。
如果 rai+11 r ≤ a i + 1 − 1 ,转移后不变,不用考虑。
如果 r>ai+11 r > a i + 1 − 1 ,第一种转移后 r r 至少会变为 r2
而第二种转移只会有 O(n) O ( n ) 个,所以总共枚举到的状态数为 O(nloga1) O ( n log ⁡ a 1 )
set s e t 储存状态,复杂度为 O(nloga1logn) O ( n log ⁡ a 1 log ⁡ n )

#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
typedef long long ll;
typedef pair<ll,ll> abcd;
typedef set<abcd>::iterator It;
const int N=200010;
set<abcd>S;
vector<abcd>g;
int k,n,m,l;
ll Ans;
ll x,lst;
int main(){
    scanf("%d%I64d",&n,&lst);
    S.insert(abcd(lst-1,0));
    for(int i=1;i<n;i++){
        scanf("%I64d",&x);
        if(x>=lst)continue;
        lst=x;
        g.clear();
        while(!S.empty()){
            It I=S.end();I--;
            if((*I).fi<x)break;
            g.push_back((*I));
            S.erase(I);
        }
        if(!(g.size()))continue;
        ll mx=0;
        for(int j=0;j<g.size();j++){
            abcd t=g[j];
            mx=max(mx,t.se+1ll*i*(t.fi-x-t.fi%x));
            S.insert(abcd(t.fi%x,t.se+1ll*i*(t.fi-t.fi%x)));
        }
        S.insert(abcd(x-1,mx));
    }
    for(It I=S.begin();I!=S.end();I++){
        abcd t=(*I);
        Ans=max(Ans,n*t.fi+t.se);
    }
    cout<<Ans<<endl;
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值