zoukankan      html  css  js  c++  java
  • Codeforces1491——C.Pekora and Trampoline(差分思维+树状数组)

    原题链接
    There is a trampoline park with n trampolines in a line. The i-th of which has strength Si.

    Pekora can jump on trampolines in multiple passes. She starts the pass by jumping on any trampoline of her choice.

    If at the moment Pekora jumps on trampoline i, the trampoline will launch her to position i+Si, and Si will become equal to max(Si−1,1). In other words, Si will decrease by 1, except of the case Si=1, when Si will remain equal to 1.

    If there is no trampoline in position i+Si, then this pass is over. Otherwise, Pekora will continue the pass by jumping from the trampoline at position i+Si by the same rule as above.

    Pekora can’t stop jumping during the pass until she lands at the position larger than n (in which there is no trampoline). Poor Pekora!

    Pekora is a naughty rabbit and wants to ruin the trampoline park by reducing all Si to 1. What is the minimum number of passes she needs to reduce all Si to 1?

    Input
    The first line contains a single integer t (1≤t≤500) — the number of test cases.

    The first line of each test case contains a single integer n (1≤n≤5000) — the number of trampolines.

    The second line of each test case contains n integers S1,S2,…,Sn (1≤Si≤109), where Si is the strength of the i-th trampoline.

    It’s guaranteed that the sum of n over all test cases doesn’t exceed 5000.

    Output
    For each test case, output a single integer — the minimum number of passes Pekora needs to do to reduce all Si to 1.

    Example
    inputCopy
    3
    7
    1 4 2 2 2 2 2
    2
    2 3
    5
    1 1 1 1 1
    outputCopy
    4
    3
    0
    Note
    For the first test case, here is an optimal series of passes Pekora can take. (The bolded numbers are the positions that Pekora jumps into during these passes.)

    [1,4,2,2,2,2,2]
    [1,4,1,2,1,2,1]
    [1,3,1,2,1,1,1]
    [1,2,1,2,1,1,1]
    For the second test case, the optimal series of passes is show below.

    [2,3]
    [1,3]
    [1,2]
    For the third test case, all Si are already equal to 1.

    题意:
    在这里插入图片描述

    思路:
    首先,贪心的考虑,从 a i > 1 a_{i}>1 ai>1的点起跳是最优的。
    然后,考虑每个点的贡献。假设当前高度为 a i a_{i} ai,那么从i点能够跳到后面的 [ i + 1 , i + s i ] [i+1,i+s_{i}] [i+1,i+si]
    我们可以确定的是,对 [ i + 2 , i + s i ] [i+2,i+s_{i}] [i+2,i+si]的贡献都为1,涉及到区间修改,最容易想到的就是差分。这样就可以计算出i点对该段区间的贡献了。关于对i+1的贡献,该部分为0,因为当i==1时,不会选择该点为起点 (从前面跳到i点再继续往后跳的情况在下文)
    假设 t i t_{i} ti表示i点被前面的点经过多少次,分下面几种情况考虑:
    1.如果 t i − s i > 1 t_{i}-s_{i}>1 tisi>1的话,因为当高度为1时就不会减少了,所以对i点不会产生贡献,从高度为1的i点会跳到i+1点,剩下的就是对i+1的贡献。
    2.如果 t i − s i < 1 t_{i}-s_{i}<1 tisi<1,说明前面的点不能使得该点变为高度为1,要再从这个点起跳。
    维护的操作用的树状数组,复杂度nlogn。

    代码:

    ///#pragma GCC optimize(2)
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<ll, ll>PLL;
    typedef pair<int, int>PII;
    typedef pair<double, double>PDD;
    #define I_int ll
    inline ll read()
    {
        ll x = 0, f = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
            if(ch == '-')f = -1;
            ch = getchar();
        }
        while(ch >= '0' && ch <= '9')
        {
            x = x * 10 + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    #define read read()
    #define closeSync ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
    #define multiCase int T;cin>>T;for(int t=1;t<=T;t++)
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    #define repp(i,a,b) for(int i=(a);i<(b);i++)
    #define per(i,a,b) for(int i=(a);i>=(b);i--)
    #define perr(i,a,b) for(int i=(a);i>(b);i--)
    ll ksm(ll a, ll b, ll p)
    {
        ll res = 1;
        while(b)
        {
            if(b & 1)res = res * a % p;
            a = a * a % p;
            b >>= 1;
        }
        return res;
    }
    const int inf = 0x3f3f3f3f;
    #define PI acos(-1)
    const double eps = 1e-8;
    const int maxn = 2e5 + 7;
    int n,a[maxn];
    ll tr[maxn];
    ll lowbit(ll x){
        return x&(-x);
    }
    void update(ll pos,ll val){
    	while(pos<=n){
    		tr[pos]+=val;
    		pos+=lowbit(pos);
    	}
    }
    ll qask(ll pos){
    	ll res=0;
    	while(pos){
    		res+=tr[pos];
    		pos-=lowbit(pos);
    	}
    	return res;
    }
    void solve(){
    	n=read;
    	memset(tr,0,sizeof tr);
    	rep(i,1,n) a[i]=read;
    	ll res=0;
    	for(int i=1;i<=n;i++){
    		int tmp=a[i]-qask(i);
    		if(tmp>1) res+=tmp-1;///还要从这个点起跳使这个点变为1
    		if(a[i]>1) update(i+2,1),update(i+a[i]+1,-1);///计算对后面点的贡献
    		if(tmp<1){
    			///该点正好可以为1,考虑对i+1的影响
    			update(i+1,1-tmp);update(i+2,tmp-1);
    		}
    	}
    	printf("%lld
    ",res);
    }
    
    int main()
    {
    	int T=read;
    	while(T--) solve();
        return 0;
    }
    
  • 相关阅读:
    备份服务器实战
    LAMP架构编译安装过程详解
    centos .7x service iptables save 错误解决方案
    Linux上安装jdk1.8和配置环境变量
    YUM源使用阿里镜像
    Linux增加swap分区的方法
    elasticsearch5.4集群超时
    职场PPT达人装酷的13条秘诀
    千古绝唱风月事,河山绘尽一人心
    前端集成解决方案
  • 原文地址:https://www.cnblogs.com/OvOq/p/14853021.html
Copyright © 2011-2022 走看看