Codeforce 1491C Pekora and Trampoline(思维+差分)

题目链接


题目大意: 有n个跳床,每个跳床有一个跳的距离,每个跳床跳一次就会使得弹跳距离减1,弹跳距离max(1,a[i])。你可以选择任意跳床选择开始,问你最少经过几个轮回才能将所有跳床弹跳距离都变成1。


思路: 差分维护
首先我们要将全部都转化成1,那么最优的方法就是从第一个大于1的弹床开始跳,这样一定是最优的。我们假设第一个是a[i],那么他第一次跳到(i+a[i])上,第二次跳到(i+a[i]-1)…知道最后一次从i点开始跳就跳到(i+2)上。一共跳了(a[i]-1)次。
注意这个地方:其实就是来积累前面跳到这个地方的.

 if(tmp<1) {
                if(i+1<=n) {
                    b[i+1]+=(1-tmp);///会前面变1走的次数
                }
                if(i+2<=n) {
                    b[i+2]-=(1-tmp);///后端维护了
                }
}
#include <set>
#include <map>
#include <queue>
#include <string>
#include<iostream>
#include<stdio.h>
#include<string.h>
#include <algorithm>
#include <math.h>
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
typedef pair<ll,ll> pii;
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define mem(a,x) memset(a,x,sizeof(a))
#define debug(x) cout << #x << ": " << x << endl;
#define rep(i,n) for(int i=0;i<(n);++i)
#define repi(i,a,b) for(int i=int(a);i<=(b);++i)
#define repr(i,b,a) for(int i=int(b);i>=(a);--i)
const int maxn=2e5+10;
#define inf 0x3f3f3f3f
#define sf scanf
#define pf printf
const int mod=1e9+7;
const int MOD=1e9+7;

inline int read() {
    int x=0;
    bool t=false;
    char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}
ll n,m,d;
ll a[maxn],b[maxn];
ll ans;
string str;
int main() {
    ll t;
    cin>>t;
    while(t--) {
        cin>>n;
        for(int i=1; i<=n; i++) {
            scanf("%lld",&a[i]);
            b[i]=0;
        }
        ans=0;
        for(int i=1; i<=n; i++) {
            b[i]+=b[i-1];///积累贡献
        ///cout<<"i  "<<i<<"b[i]***"<<b[i]<<endl;
            ll tmp=a[i]-b[i];///是否还需要跳
            if(tmp>1) ans+=tmp-1;///需要
            if(a[i]>1) {
                if(i+2<=n) {///最后一次跳
                    b[i+2]++;///维护差分
                }
                if(i+a[i]+1<=n) {
                    b[i+a[i]+1]--;///维护差分
                }
            }
            if(tmp<1) {
                if(i+1<=n) {
                    ///cout<<i<<"(1-tmp)"<<1-tmp<<endl;
                    ///cout<<"b[i+1]"<<b[i+1]<<" ";
                    b[i+1]+=(1-tmp);///会前面变1走的次数
                    ///cout<<"ab[i+1]"<<b[i+1]<<endl;
                }
                if(i+2<=n) {
                    ///cout<<i<<"(1-tmp)"<<1-tmp<<endl;
                    ///cout<<"b[i+2]"<<b[i+2]<<" ";
                    b[i+2]-=(1-tmp);///后端维护了
                    ///cout<<"ab[i+2]"<<b[i+2]<<endl;
                }
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值