【题解】P4343 [SHOI2015]自动刷题机

原题地址

简化题面:一个数,初始为0。\(l\)次操作,每次给这个数加上 \(xi\)\(xi\)可能为负),如果其小于0则变成0,如果大于等于\(n\)则变成0并给\(ans\)加1。已知最后的\(ans\)等于\(k\),求\(n\)可能的最小值和最大值。如果没有满足条件的\(n\),输出-1。

对于一眼看到此题,很难想到二分来做,考虑怎么想到的二分

举个栗子

假如两个\(n\),一个8一个9,假如第一次增加9,对于\(n=8\)来说剩余1,对于\(n=9\)来说剩余0,在剩余的增加次数中无论怎样8总会领先于9\(ans\)到达\(k\),因此可见对于不同的\(n\),对于到达\(k\)\(ans\)的贡献是单调的,可以进行二分

想到了二分,此题就很好做了,我们二分\(n\),对于答案的判断直接进行题面模拟的,逐步压缩空间直到符合答案

有关二分

对于二分有两种格式,下面简单提一下

对于求符合答案区间的最小值,也就是左边箭头所指的值,我们的二分过程如下

while(l < r){
	int mid = (l + r) >> 1;
    if(a[mid] >= x) r = mid;else l = mid + 1;
}
return a[l];

对于最大值,也就是右边箭头所指的值,我们的二分过程如下

while(l < r){
	int mid = (l + r + 1) >> 1;
    if(a[mid] <= x) l = mid; else r = mid - 1;
}
return a[l];

个人认为二分类型的题很练人的细节程度,建议仔细品一品过程并且自己模拟一下~

\(Code\)

#include<bits/stdc++.h>
    
#define LL long long
    
#define int long long

#define _ 0
    
using namespace std;
    
/*Grievous Lady*/
    
template <typename T> void read(T & t){
    t = 0;int f = 1;char ch = getchar();
    while(ch < '0' || ch > '9'){if(ch == '-')f =- 1;ch = getchar();}
    do{t = t * 10 + ch - '0';ch = getchar();}while(ch >= '0' && ch <= '9');t *= f;
}

#define INF 0x3f3f3f3f3f3f3f3fLL

const int kato = 1e5 + 10;

int a , k;

int x[kato];

inline int judge(int mid){
    int sum = 0 , tot = 0;
    for(int i = 1;i <= a;i ++){
        sum += x[i];
        if(sum < 0) sum = 0;
        if(sum >= mid) tot ++ , sum = 0;
    }
    return tot;
}

inline int Ame_(){
    read(a);read(k);
    for(int i = 1;i <= a;i ++){
        read(x[i]);
    }
    int la = 1 , ra = INF , ansa = INF;
    while(la < ra){
        int mida = (la + ra) >> 1;
        if(judge(mida) <= k){
            ra = mida;
        }
        else la = mida + 1;
        // cout << ansa << '\n';
    }
    if(judge(la) == k) ansa = la;
    if(ansa != INF) printf("%lld " , ansa);
    else printf("-1 ");
    int lb = 1 , rb = INF , ansb = INF;
    while(lb < rb){
        int midb = (lb + rb + 1) >> 1;
        if(judge(midb) >= k){ 
            lb = midb;
            // if(judge(lb) == k) ansb = lb;
        }
        else rb = midb - 1;
    }
    if(judge(lb) == k) ansb = lb;
    if(ansb != INF) printf("%lld\n" , ansb);
    return ~~(0^_^0);
}
    
int Ame__ = Ame_();
    
signed main(){;}
posted @ 2020-08-01 13:33  Ame_sora  阅读(168)  评论(0编辑  收藏  举报