洛谷P4343 [SHOI2015]自动刷题机

题目

易得该题目中的\(n\)\(k\)具有单调性,满足二分的性质,因此该题目而已用二分来枚举\(n\),然后对于每个\(n\)模拟出它所对应的\(k\),然后注意注意代码细节,并且当当前\(k\)等于题目要求的\(k\)时,要分别向左和右二分,才能找出所有情况。

#include <bits/stdc++.h>
#define N 3000011   
#define int long long
using namespace std;
int n, k, x[N], sum[N], maxn, minn = 2147483647124544;
int check(int mid)
{
    int l = 1, now = 0, tot = 0;
    while (l <= n)//这里是不能二分的,因为不满足二分单调性。 
    {
        while (now < mid && l <= n)
        {
            now += x[l++];
            now = max(now, 0LL);
        }   
        if (now >= mid) 
        tot++, now = 0;//此处l不能++, 因为循环里已经++了 
    }
    return tot;
}   
signed main()
{   
    scanf("%lld%lld", &n, &k);  
    for (int i = 1; i <= n; i++)
    {
        scanf("%lld", &x[i]); 
        sum[i] = sum[i - 1] + x[i];
        if (sum[i] < 0) sum[i] = 0;
    }
//  printf("%lld ", check(3));
    int l = 1LL, r = 1000000000000LL;//二分n
    while (l <= r)
    {
        int mid = (l + r) >> 1;
        if (check(mid) > k)//如果最终的结果比k大,n越大,k越小 
            l = mid + 1;
        if (check(mid) < k)
            r = mid - 1;
        if (check(mid) == k)
        {
            minn = min(minn, mid), maxn = max(maxn, mid); 
            r = mid - 1;
        }
    }
    l = 1LL, r = 1000000000000LL;
    while (l <= r)
    {
        int mid = (l + r) >> 1;
        if (check(mid) > k)//如果最终的结果比k大,n越大,k越小 
            l = mid + 1;
        if (check(mid) < k)
            r = mid - 1;
        if (check(mid) == k)
        {
            minn = min(minn, mid), maxn = max(maxn, mid); 
            l = mid + 1;
        }
    }
    if (minn == 2147483647124544)
        printf("-1"), exit(0);
    printf("%lld %lld", minn, maxn);
    return 0;
}   

猜你喜欢

转载自www.cnblogs.com/liuwenyao/p/11715574.html