ZOJ 3424 Rescue(和式变形递推公式降低复杂度)

21 篇文章 0 订阅
2 篇文章 0 订阅

Rescue
Time Limit: 3 Seconds Memory Limit: 65536 KB
The princess is trapped in a magic place. In this place, there are N magic stones. In order to rescue the princess, you should destroy all the stones.

The N stones are in a straight line. We number them as s1, s2, … sn from left to right. Each stone has a magic strength m1, m2, … mn. You have a powerful skill that can do some damage to the stones. To release the skill, you should stand to the right of some stone (si). Then you throw a power ball towards left. Initially, this ball has a power of p. When it hits a stone, it will do some damage to the stone and its power will be decreased, and the ball will continue to fly left to the next stone if its power is still positive. Formally, if you stand to the right of si and the power ball’s initial power is p, then the ball will do Max(0, p - (i - j) * (i - j)) damage to sj, for each j <= i. So from this formula, we can see that the damage to stone sj is only determined by the initial power of the ball and the number of stones between si and sj.

A stone is destroyed if the accumulated damage you do is larger than its magic strength. Note that even if a stone is destroyed, it will not disappear; your magic ball will do damage to it and the power will be decreased by that stone. You are not strong enough so that you can release at most k magic balls. It will cost a lot of energy if the power of the magic ball is too high. So what is the minimum value of p with which you can destroy all the magic stones, with no more than k magic balls? You can choose where to release each magic ball as your will, and the power of the ball must be a positive integer.

Input

The first line is the number of cases T (T ≤ 100). For each case, the first line gives two integers n, k (1 ≤ n ≤ 50000, 1 ≤ k ≤ 100000). The second line are n integers, giving m1, m2, … mn (1 ≤ mi ≤ 109).

Output

Print minimum possible p in a line.

Sample Input

2
1 1
1
3 1
1 4 5
Sample Output

2
6
Author: HANG, Hang
Source: The 2010 ACM-ICPC Asia Chengdu Regional Contest

题目大意:

  有一排石头,每个石头都有一个自己的血量,每次可以站在一个石头的位置上攻击左边的石头,攻击力为 p ,站在位置i时,在位置 j 的石头受到的伤害为Max(0,p(ij)×(ij))。要求攻击 K 次,求能够打爆所有石头的最小攻击力p

解题思路:

  首先很容易想到二分 p ,然后进行check。
  对于check我们也比较容易想到:从左往右扫,根据之前的攻击算出当前石头的剩余血量,然后站在这里用最小的攻击次数把剩下的血打完,重复知道攻击完所有石头,统计总攻击次数是否小于等于K即可。不过这样没次计算剩余血量都需要把右边的石头扫一遍,时间复杂度为 O(N2) N 最大可以达到5×104,显然会TLE。
  我们可以发现,一对位置的伤害衰减为 (ij)2=i22ij+j2 ,当 j 向左移动一个单位的时候,伤害衰减就变成了(i(j1))2=i2+2i2ij+j22j+1,就是增加了 2(ij)+1 。所以我们维护当前的对数和每一对的距离差就可以由右边一个单位的距离衰减 O(1) 得到,我们也就可以进行 O(N) 的check,也就可以通过这道题了。

AC代码:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <string>
#include <ctime>
#include <bitset>
using namespace std;
#define INF 0x3f3f3f3f3f3f3f3f
#define ULL unsigned long long
#define LL long long
#define fi first
#define se second
#define mem(a, b) memset((a),(b),sizeof(a))
#define sqr(x) ((x)*(x))

const int MAXN=50000+3;
int N, K, hp[MAXN];
int hit[MAXN];//当前石头额外需要的攻击次数

bool judge(LL x)
{
    int res=0, cnt=0;//总攻击次数,当前攻击次数
    LL less2=0;//距离衰减
    LL less=0;
    for(int i=N-1, j=i;i>=0;--i)//i: 当前石头位置,j: 站位
    {
        while(sqr((LL)(j-i))>=x)//去除掉因为离得太远,无法影响到当前位置的攻击位置
        {
            less2-=hit[j]*(sqr((LL)(j-i-1)));
            less-=hit[j]*(j-i-1);
            cnt-=hit[j];
            --j;
        }
        //对于每一对来说,石子每往左移一位,衰减增加2*(j-i)+1
        less2+=less*2+cnt;//更新距离衰减
        less+=cnt;//更新差值
        if(hp[i]<(cnt*x-less2))//当前石头已经被打爆,不需要再站在当前位置攻击
            hit[i]=0;
        else hit[i]=(hp[i]-cnt*x+less2)/x+1;//得到为了把这个石头打爆,需要在当前位置攻击多少次
        cnt+=hit[i];//更新对数
        res+=hit[i];
        if(res>K)
            return false;
    }
    return res<=K;
}

int main()
{
    int T_T;
    scanf("%d", &T_T);
    while(T_T--)
    {
        scanf("%d%d", &N, &K);
        for(int i=0;i<N;++i)
            scanf("%d", &hp[i]);
        LL l=0, r=INF;
        while(r-l>1)
        {
            LL mid=(l+r)>>1;
            if(judge(mid))
                r=mid;
            else l=mid;
        }
        printf("%lld\n", r);
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值