hdu 3717 Rescue

Rescue

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


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

 题意:给出n块石头,每块都有一个承受的伤害值mi,你现在需要把所有石头都销毁。你每次找最右的没有被

销毁的石头投放魔法石,魔法石可以从右到左对石头造成伤害,加入你投放的位置的是 j ,

那么对i 造成的伤害是max(0,p-(i-j)*(i-j)) 。对于石头i ,如果伤害累加 > mi那么就会被销毁,

注意不会消失。最多可以投放 k次魔法石,求最小的p 

思路:很容易想到二分p ,现在判断二分的是p 是否满足

如果你投放一个魔法石在 j ,那么它造成的伤害范围是可以算出来的 (j - sqrt(p))~j 

因为(i-j)^2 = i*i+j*j-2*i*j ;

所以我们可以用 sum1记录所有的j 之和,sum2记录所有的j*j 之和,统计记录加的个数cnt。

我们计算到 i 时,它已经受的伤害衰减就是v= sum2+i*i*cnt-2*sum1*i;

cnt*p-v就是它已经受的伤害之和;

这样就很容易搞了,注意伤害只是一个范围的,出了范围把它减去就好了

还有注意对于每块石头可以投多次魔法石

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<set>
#include<stack>
#include<map>
#include<ctime>
#include<bitset>
#define LL long long
#define ll long long
#define INF 0x3f3f3f3f
#define maxn 50010
#define eps 1e-6
#define mod 1000000007
using namespace std;

int val[maxn];
LL add1[maxn],add2[maxn],cnt1[maxn] ;
bool check(LL x,int n,int k )
{
    int i,j,tt=sqrt(x+0.0) ,hehe;
    LL sum1,sum2,cnt,v ,su,ans=0;
    sum1=sum2=cnt=0;
  /*  memset(add1,0,sizeof(add1)) ;
    memset(add2,0,sizeof(add2)) ;
    memset(cnt1,0,sizeof(cnt1)) ;*/
    for( i = n ; i >= 1 ;i--)
        add2[i]=add1[i]=cnt1[i]=0;
    for( i = n ; i >= 1 ;i--)
    {
        sum1 -= add1[i] ;
        sum2 -= add2[i] ;
        cnt -= cnt1[i] ;

        v=sum2+(LL)i*i*cnt-2*sum1*i;
        su=cnt*x-v;

        if(su > val[i]) continue ;
        hehe=val[i];
        hehe -= su ;
        su = hehe/x;
        su++;
        ans+=su;
        if(ans>k) return false;
        sum1 += i*su ;
        sum2 += (LL)i*i*su ;
        cnt+=su;
        j = i-tt-1 ;
        if(j>=1)
        {
            add1[j] += i*su ;
            add2[j] += i*su*i ;
            cnt1[j]+=su;
        }
    }
    return true;
}
int main()
{
    int i,n,m,j,k;
    LL L,R,ans,mid ;
    int T ;
   // freopen("in.txt","r",stdin);
    cin >> T ;
    while(T--)
    {
        scanf("%d%d",&n,&k) ;
        for( i = 1 ; i <= n;i++){
            scanf("%d",&val[i]);
        }
        R=1e12;
        L=1;
        ans=-1;
        while(L<=R)
        {
            mid=(L+R)>>1 ;
            if(check(mid,n,k))
            {
                ans=mid;
                R=mid-1;
            }
            else L =mid+1;
        }
        printf("%I64d\n",ans) ;
    }
    return 0 ;
}
View Code

 

posted @ 2014-11-01 00:41  _log__  阅读(320)  评论(0编辑  收藏  举报