类似区间覆盖的问题,每个弓箭手可以给半径r的区域加防御力,有一些弓箭手未被部署,问你怎么部署可以使得防御力最小值最大.
当然想到是二分,但是二分之后我一开始想的是用树状数组来获得区间和,判断行不行,(一旦不行就给最左边的加这是很容易想到的).然而t了…我优化了好久,最后发现,有且只有最后一组过不了,并且答案已经显示出来了…
然后想到用滑动窗口来判断当前区间和…这个就容易很多..
然而发现并没有快多少,这题卡空间和时间都很爆炸…去看一下题解好了T^T
(确实快了很多…把cin换成scanf就好…这1.5s,真是精髓..)
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
#define debug(x) std::cerr << #x << " = " << (x) << std::endl
typedef long long LL;
const int MAXN = 5e5+17;
LL a[65][MAXN];
int main(int argc ,char const *argv[])
{
#ifdef noob
freopen("Input.txt","r",stdin);freopen("Output.txt","w",stdout);
#endif
LL n,d,k;
cin>>n>>d>>k;
for (int i = 0; i < n; ++i)
{
cin>>a[0][i];
for (int j = 1; j < 65; ++j)
a[j][i] = a[0][i];
}
LL l = 0,r = 2e18,osum =0,dap=0;
for (int i = 0; i <= d; ++i)
osum+=a[0][i];
while(r-l>1)
{
LL mid = (l+r)/2,tk = k;
bool can = true;
LL sum = osum;
for (int i = 0; i < n; ++i)
{
LL to = (i+d)<n?(i+d):(n-1);
if(sum<mid)
{
if(tk>=mid-sum)
tk-=(mid-sum),a[dap][to]+=(mid-sum),sum = mid;
else
{
can = false;
break;
}
}
if(i+1+d<n)
sum+=a[dap][i+1+d];
if(i-d>-1)
sum-=a[dap][i-d];
}
if(can)
l = mid;
else
r = mid;
dap++;
}
cout<<l<<endl;
return 0;
}