Codeforces 940E

940E - Cashback

思路:

dp+rmq

可以证明最后划分的区间可以由长度为1和长度为c的区间组成的,这样就可以用O(n)的dp求了,区间最小值随便拿什么维护都可以

状态:dp[i]表示到i这个位置为止的最小划分和

初始状态:dp[0]=0

目标状态:dp[n]

状态转移:dp[i]=min(dp[i-1]+a[i],dp[i-c]+sum[i]-sum[i-c]+minmum(i-c+1,i))

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pb push_back
#define mp make_pair
#define ls rt<<1,l,m
#define rs rt<<1|1,m+1,r
#define pli pair<ll,int>
#define mem(a,b) memset(a,b,sizeof(a))

const int N=1e5+5;
const int INF=0x7f7f7f7f;
int a[N],tree[N<<2],cnt;
ll sum[N],dp[N];
void push_up(int rt){
    tree[rt]=min(tree[rt<<1],tree[rt<<1|1]);
}
void build(int rt,int l,int r){
    if(l==r){
        cin>>a[++cnt];
        tree[rt]=a[cnt];
        return ;
    }
    int m=(l+r)>>1;
    build(ls);
    build(rs);
    push_up(rt);
}
int query(int L,int R,int rt,int l,int r){
    if(L<=l&&r<=R){
        return tree[rt];
    }
    int ans=INF,m=(l+r)>>1;
    if(L<=m)ans=min(ans,query(L,R,ls));
    if(R>m)ans=min(ans,query(L,R,rs));
    return ans;
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int n,c;
    cin>>n>>c;
    build(1,1,n);
    for(int i=1;i<=n;i++)sum[i]=sum[i-1]+a[i];
    for(int i=1;i<=n;i++){
        if(i-c>=0)dp[i]=min(dp[i-1]+a[i],dp[i-c]+sum[i]-sum[i-c]-query(i-c+1,i,1,1,n));
        else dp[i]=dp[i-1]+a[i];
    }
    cout<<dp[n]<<endl;
    return 0;
}
原文地址:https://www.cnblogs.com/widsom/p/8494892.html