题目传送门
首先这个题你从右往左开始贪心是最优的,因为在把最后数给操作完时前面的数也被多少消耗了亿点,所以这个题的思路就出来了
我的做法是用
a
[
i
]
a[i]
a[i]数组来存储当前位置需要多少个k来消耗,然后往前转移的时候,比如说前进了一位,那么它的消耗就比它的后一位-k(通过变量来实现)
还有一堆细节是这个
i
∼
i
+
k
−
1
i \sim i+k-1
i∼i+k−1区间衍生的
- 数组的上限,这个很烦人,因为操作里面涉及 a [ i + k + 1 ] a[i+k+1] a[i+k+1],所以你的数组要开 i + k i+k i+k
- 你的 1 ∼ k − 1 1 \sim k-1 1∼k−1区间的长度明显不可能达到k,所以你要把循环拆开来跑
- 当你在往前循环的时候,你会超过后面某个区间,所以要把 a [ i + k − 1 ] a[i+k-1] a[i+k−1]的贡献去掉
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define ll long long
using namespace std;
const int N=6e5+10;//因为数组的操作范围最大是i+k-1,所以数组得开到i+k
template<class T> inline T &read(T &x){
bool f=1;x=0;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) f^=(ch=='-');
for(; isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+(ch^48);
return f?x:(x=-x);
}
template<class T> inline void write(T x){
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar((x%10)^48);
}
ll n,k,a[N],b[N],sum,ans,op;
int main() {
read(n),read(k);
for(int i=1;i<=n;++i) read(b[i]);
for(int i=n;i>=k;i--){
if(b[i]>sum){
a[i]=(b[i]-sum)/k+((b[i]-sum)%k!=0);//当前这一位操作几次
op+=a[i],ans+=a[i];//op是为了方便更新sum而生
sum+=a[i]*k;
}
sum-=op;//a[i]*(k-1)是当前这一位的前一位的累加值
op-=a[i+k-1];//范围是i~i+k-1,再往前执行就超出范围了,所以把区间最右边的贡献去掉
}
for(int i=k-1;i;i--){//这个范围下的答案自然达不到k,所以单独讨论
if(b[i]>sum){
a[i]=(b[i]-sum)/i+((b[i]-sum)%i!=0);
op+=a[i],ans+=a[i];
sum+=a[i]*i;
}
sum-=op;
op-=a[i+k-1];
}
write(ans);
return 0;
}