Progressions Covering

题目传送门
首先这个题你从右往左开始贪心是最优的,因为在把最后数给操作完时前面的数也被多少消耗了亿点,所以这个题的思路就出来了

我的做法是用 a [ i ] a[i] a[i]数组来存储当前位置需要多少个k来消耗,然后往前转移的时候,比如说前进了一位,那么它的消耗就比它的后一位-k(通过变量来实现)
还有一堆细节是这个 i ∼ i + k − 1 i \sim i+k-1 ii+k1区间衍生的

  • 数组的上限,这个很烦人,因为操作里面涉及 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 1k1区间的长度明显不可能达到k,所以你要把循环拆开来跑
  • 当你在往前循环的时候,你会超过后面某个区间,所以要把 a [ i + k − 1 ] a[i+k-1] a[i+k1]的贡献去掉
#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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值