Codeforces940 E. Cashback(思维+dp+rmq)

题意:

Codeforces940 E. Cashback(思维+dp+rmq)
数据范围:n,c<=1e5

解法:

这个向下取整很关键:
1.当k<c时,k/c=0,那么就是一个也不删,
等价于划分为k个长度为1的区间.
2.当k=pc时,k/c=p,那么就是删前p小,
发现不会比p个长度为c的区间更优,因此直接取长度为c.

综上得,长度的取值只能是1或者c.

令d[i]表示前i个数的最小值,
那么d[i]可由d[i-1]或d[i-c]转移,转移方程:
1.d[i]=min(d[i],d[i-1]+a[i]),
2.d[i]=min(d[i],d[i-1]+sum[i]-sum[i-c]-mi(i-c+1,i)).

查询区间min需要加一个rmq数据结构.

code:

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=1e5+5;
int sum[maxm];
int d[maxm];
int a[maxm];
int n,c;
struct ST{
    static const int maxd=20;
    int mi[maxm][25];
    int lg2[maxm];
    void init(){
        lg2[1]=0;
        for(int i=2;i<maxm;i++){
            lg2[i]=lg2[i-1];
            if((i&(i-1))==0)lg2[i]++;
        }
        //
        for(int i=1;i<=n;i++){
            mi[i][0]=a[i];
        }
        for(int j=1;j<=maxd;j++){
            for(int i=1;i+(1<<j)-1<=n;i++){
                mi[i][j]=min(mi[i][j-1],mi[i+(1<<(j-1))][j-1]);
            }
        }
    }
    int ask(int l,int r){
        int k=lg2[r-l+1];
        return min(mi[l][k],mi[r-(1<<k)+1][k]);
    }
}T;
signed main(){
    cin>>n>>c;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        sum[i]=sum[i-1]+a[i];
    }
    T.init();
    for(int i=1;i<=n;i++){
        d[i]=1e18;
        d[i]=min(d[i],d[i-1]+a[i]);
        if(i>=c){
            d[i]=min(d[i],d[i-c]+sum[i]-sum[i-c]-T.ask(i-c+1,i));
        }
    }
    cout<<d[n]<<endl;
    return 0;
}

上一篇:2020ICPC 江西省赛 H.Sequence(线段树+二分)


下一篇:神经网络高维互信息计算Python实现(MINE)