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 }