【LGR-081】洛谷 1 月月赛 & EZEC R5 Div.2

题目:P7287 「EZEC-5」魔法

分析:

做法一定是先多次整体加1,再多次整体x2。
考虑到 * 2的次数是log级别的,可以先枚举 * 2的次数,然后再二分+1的次数,然后二分的judge里面写个判断最大连续子段和。

代码:

#include 
using namespace std;
typedef long long ll;//三年竞赛一场空,不开long long见祖宗
//typedef __int128 lll;
#define print(i) cout << "debug: " << i << endl
#define close() ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define mem(a, b) memset(a, b, sizeof(a))
#define pb(a) push_back(a)
#define x first
#define y second
typedef pair<int, int> pii;
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const int maxn = 2e5 + 10;
const int inf = 0x3f3f3f3f;
ll n, a, b, s;
ll v[maxn];

bool judge(ll num1, ll num2)
{
     
    ll sum = 0;
    for(int i = 1; i <= n; i++)
    {
     
        sum = max(0ll, sum) + (v[i] + num1) * (1ll << num2);
        if(sum >= s) return true;
    }
    return false;
}

int main()
{
     
    cin >> n >> a >> b >> s;
    ll maxx = -2e18;
    for(int i = 1; i <= n; i++) cin >> v[i], maxx = max(maxx, v[i]);
    ll res = 2e18;
    for(int i = 0; i <= 32; i++)
    {
     
        ll l = 0, r = 2e9;
        while(l <= r)
        {
     
            ll mid = l + r >> 1;
            if(judge(mid, i)) r = mid - 1;
            else l = mid + 1;
        }
        if(judge(l, i))
            res = min(res, a * l + b * i);
    }
    cout << res << endl;
}

你可能感兴趣的:(二分)