hdu 3717

思路:二分答案,然后模拟消灭石头的过程;

如果单纯的暴力模拟的话,肯定会T的;

所以要用到一定的技巧来维护;

在网上看到大神们用O(n)的复杂度来优化,真心orz;

原理是这样的:用一个变量sum_2存前面所有的对当前石头造成影响的冲击波的损失的能量和;

所以对于当前的石头所需要的新的冲击波的数量为:(当前石头的能量值-前面有影响的冲击波数*能量x+sum_2)/能量x+1;

然后就是维护sum_2了!

维护sum_2要利用这个公式:(x+1)^2=x^2+2*x+1;

 1 #include<iostream>
 2 #define maxn 50005
 3 #define ll long long
 4 using namespace std;
 5 ll cnt[maxn];
 6 ll num[maxn];
 7 int n,k,t;
 8 bool check(ll x)
 9 {
10     ll sum_2=0,sum_1=0,sum=0,ans=0;
11     int j=n-1;
12     for(int i=n-1;i>=0;i--)
13     {
14         if(j>i)
15         {
16             while((j-i)*(j-i)>=x)
17             {
18                 sum_2-=cnt[j]*(j-i-1)*(j-i-1);
19                 sum_1-=cnt[j]*(j-i-1);
20                 sum-=cnt[j];
21                 j--;
22             }
23         }
24         sum_2+=2*sum_1+sum;
25         sum_1+=sum;
26         ll y=num[i]-sum*x+sum_2;
27         if(y<0)cnt[i]=0;
28         else cnt[i]=y/x+1;
29         sum+=cnt[i];
30         ans+=cnt[i];
31     }
32     return ans<=k;
33 }
34 
35 
36 int main()
37 {
38     cin>>t;
39     while(t--)
40     {
41         cin>>n>>k;
42         for(int i=0;i<n;i++)cin>>num[i];
43         ll l=1,r=1e12;
44         while(l<r)
45         {
46             ll mid=(l+r)>>1;
47             if(check(mid))r=mid;
48             else l=mid+1;
49         }
50         cout<<l<<endl;
51     }
52     return 0;
53 }
View Code
原文地址:https://www.cnblogs.com/yours1103/p/3414737.html