HDU 3717 Rescue 枚举 模拟

Rescue

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 768    Accepted Submission(s): 183


Problem Description
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 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 ≤ m ≤ 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
2010 Asia Chengdu Regional Contest 

1.题目中要求最小的p值,但直接求很难,于是想到枚举出p的值,然后根据这个确定的p,计算出击毁所有的石块所需的冲击波的个数,与k相比较,枚举p的时候,可以根据ans与k的关系进行二分查找

2.问题的关键是根据给定的p确定冲击波的个数,这里需要使用三个变量

    sum_2:前面所有的对当前石头造成影响的冲击波的损失的能量和
    sum_1:长度
    sum  :前面有影响的冲击波数

#include<iostream>
#define maxn 50005
#define ll long long
using namespace std;
ll cnt[maxn];//每一个石块所需的冲击波的数量
ll num[maxn];//每一个石块的魔法值
int n,k,t;
bool check(ll x)//计算在p为x的情况下击毁所有石块所需的冲击波数量
{
    ll sum_2=0,sum_1=0,sum=0,ans=0;
    //sum_2:前面所有的对当前石头造成影响的冲击波的损失的能量和
    //sum_1:长度
    //sum  :前面有影响的冲击波数
    int j=n-1;
    for(int i=n-1;i>=0;i--)
    {
        if(j>i)
        {
            while((j-i)*(j-i)>=x)
            {
                sum_2-=cnt[j]*(j-i-1)*(j-i-1);
                sum_1-=cnt[j]*(j-i-1);
                sum-=cnt[j];
                j--;
            }
        }
        sum_2+=2*sum_1+sum;
        sum_1+=sum;
        ll y=num[i]-sum*x+sum_2;
        if(y<0)cnt[i]=0;
        else cnt[i]=y/x+1;
        sum+=cnt[i];
        ans+=cnt[i];
    }
    return ans<=k;//返回所需冲击波的数量与k的关系
}


int main()
{
    cin>>t;
    while(t--)
    {
        cin>>n>>k;
        for(int i=0;i<n;i++)cin>>num[i];
        ll l=1,r=1e12;//初始化左右区间
        while(l<r)//二分枚举答案
        {
            ll mid=(l+r)>>1;
            if(check(mid))r=mid;
            else l=mid+1;
        }
        cout<<l<<endl;
    }
    return 0;
}





你可能感兴趣的:(枚举,模拟,HDU,rescue,3717)