cf Castle Defense(二分+滑动窗口)

类似区间覆盖的问题,每个弓箭手可以给半径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;   
}

猜你喜欢

转载自blog.csdn.net/m0_37802215/article/details/79699505