ZOJ 3424 Rescue(和式變形遞推公式降低複雜度)

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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章