C. Pekora and Trampoline
题意:
有n个蹦床排成一列,第i个蹦床有弹力值s[i],在当前位置你可以往右跳到第i + s[i]个蹦床如果i + s[i] > n
那么这次连跳结束,而且每跳一次弹力值减一但最小减到1
问你最少需要多少次起跳(就是第一次跳而不经过其他跳到),使得所有的蹦床弹力值都变为1
分析:
只有从前面的蹦床跳到后面才使得后面的蹦床少跳!
那么我只需要统计i前面的(1~i-1)所有蹦床对它少跳贡献多少,显然s[i] 会对 i + 2 ~ i + s[i]的后面所有蹦床有贡献
所以就用差分+前缀和来分别标记该蹦床对后面的蹦床的贡献,以及查询该蹦床前面的蹦床对它的贡献
这里有个坑就是 如果别人弹力值已经变为1了或者前面的贡献总和使它变为1还有剩余的贡献,那么这个贡献会顺延到他的下一个蹦床
代码
#include<bits/stdc++.h>
using namespace std;
const int N = 5e3 + 5;
#define ll long long
int s[N],presum[N];
int main()
{
int t,n;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i = 1;i <= n;i++)
scanf("%d",&s[i]);
memset(presum,0,sizeof presum);
ll cnt = 0;
for(int i = 1;i <= n;i++)
{
presum[i] += presum[i-1];
int nd = s[i] - presum[i] - 1;
cnt += max(nd,0);
if(i + 2 <= n) presum[i + 2] += 1,presum[min(i + s[i] + 1,n + 1)] -= 1;
if(nd < 0 && i + 1 <= n) presum[i+1] += -nd,presum[i + 2] -= -nd;
//上面这一行代码就是说如果别人弹力值已经变为1了或者前面的贡献总和使它变为1还有剩余的贡献,
//那么这个贡献会顺延到他的下一个蹦床
}
printf("%lld\n",cnt);
}
return 0;
}

浙公网安备 33010602011771号