• ZOJ 4062


    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4062

    题意:

    现在在一条 $x$ 轴上玩植物大战僵尸,有 $n$ 个植物,编号为 $1 sim n$,第 $i$ 个植物的位置在坐标 $i$,成长值为 $a_i$,初始防御值为 $d_i$。

    现在有一辆小车从坐标 $0$ 出发,每次浇水操作必须是先走 $1$ 单位长度,然后再进行浇水,植物被浇一次水,防御值 $d_i+=a_i$。

    现在知道,小车最多进行 $m$ 次浇水操作,而已知总防御值为 $min{d_1,d_2,d_3,cdots,d_n}$。求最大的总防御值为多少。

    Input

    There are multiple test cases. The first line of the input contains an integer $T$, indicating the number of test cases. For each test case:

    The first line contains two integers $n$ and $m$ ($2 le n le 10^5, 0 le m le 10^{12}$), indicating the number of plants and the maximum number of steps the robot can take.

    The second line contains integers $a_1,a_2, cdots, a_n$ ($1 le a_i le 10^5$), where indicates the growth speed of the -th plant.

    It's guaranteed that the sum of in all test cases will not exceed $10^6$.

    Output

    For each test case output one line containing one integer, indicating the maximum defense value of the garden DreamGrid can get.

    Sample Input
    2
    4 8
    3 2 6 6
    3 9
    10 10 1

    Sample Output
    6
    4

    题解:

    二分总防御值,对于固定的防御值 $d$,显然花园里的每个植物都要不小于 $d$,因此贪心地从左往右寻找每一个防御值小于 $d$ 的植物,对它和它右侧的植物反复浇水。

    AC代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn=1e5+10;
    
    int n;
    ll m;
    ll a[maxn],d[maxn];
    
    ll judge(ll k)
    {
        memset(d,0,(n+1)*sizeof(ll));
        ll cnt=0;
        for(int i=1;i<=n;i++)
        {
            if(i==n && d[i]>=k) break;
            cnt++, d[i]+=a[i];
            if(d[i]>=k) continue;
    
            ll tmp=(k-d[i])/a[i]+((k-d[i])%a[i]>0);
            cnt+=2*tmp;
            d[i]+=tmp*a[i];
            d[i+1]+=tmp*a[i+1];
        }
        return cnt;
    }
    
    int main()
    {
        ios::sync_with_stdio(0);
        cin.tie(0);
    
        int T;
        cin>>T;
        while(T--)
        {
            cin>>n>>m;
            ll mn=1e5+10;
            for(int i=1;i<=n;i++) cin>>a[i], mn=min(mn,a[i]);
    
            ll l=0, r=mn*m;
            while(l<r)
            {
                ll mid=(l+r+1)>>1;
                if(judge(mid)<=m) l=mid;
                else r=mid-1;
            }
            cout<<l<<'
    ';
        }
    }

    注:

    这题的右区间不要直接设成 $1e17$,因为这样当 $a[i]$ 都是小数据的时候 $judge$ 函数里的 $cnt$ 会爆long long。

    不妨设成 $a_i$ 最小值的 $m$ 倍,很容易证明最后的答案是不会超过这个值的。

  • 相关阅读:
    转:.net面试题及答案(一)
    高兴!
    游标中LOCAL的意思
    九度 1333
    在进程槽中为进程分配一个空闲位置并分配一个进程号
    USACO Section 1.2 Milking Cows
    九度 1334
    USACO Section 1.3 Mixing Milk
    USACO Section 1.3 Calf Flac
    USACO Section 1.3 Prime Cryptarithm
  • 原文地址:https://www.cnblogs.com/dilthey/p/9941711.html
Copyright © 2020-2023  润新知