题意:
数据范围: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;
}