1. 程式人生 > 實用技巧 >【luoguP4343】自動刷題機

【luoguP4343】自動刷題機

題目

題目背景

曾經發明瞭訊號增幅儀的發明家 SHTSC 又公開了他的新發明:自動刷題機——一種可以自動 AC 題目的神祕裝置。

題目描述

自動刷題機刷題的方式非常簡單:首先會瞬間得出題目的正確做法,然後開始寫程式。每秒,自動刷題機的程式碼生成模組會有兩種可能的結果:

1.寫了 x 行程式碼
2.心情不好,刪掉了之前寫的 y 行程式碼。(如果 y 大於當前程式碼長度則相當於全部刪除。)

對於一個 OJ,存在某個固定的正整數長度 n,一旦自動刷題機在某秒結束時積累了大於等於 n 行的程式碼,它就會自動提交併 AC 此題,然後新建一個檔案(即棄置之前的所有程式碼)並開始寫下一題。SHTSC 在某個 OJ 上跑了一天的自動刷題機,得到了很多條關於寫程式碼的日誌資訊。他突然發現自己沒有記錄這個 OJ 的 n 究竟是多少。所幸他通過自己在 OJ 上的 Rank 知道了自動刷題機一共切了 k 道題,希望你計算 n 可能的最小值和最大值。

輸入格式

第一行兩個整數 l,kl , kl,k,表示刷題機的日誌一共有 l 行,一共了切了 k 題。

接下來 l 行,每行一個整數 xi​,依次表示每條日誌。若 xi≥0,則表示寫了 xi行程式碼,若 xi<0,則表示刪除了 -xi行程式碼。

輸出格式

輸出一行兩個整數,分別表示 n 可能的最小值和最大值。
如果這樣的 n 不存在,請輸出一行一個整數 −1。

連結:

https://www.luogu.com.cn/problem/P4343

思路

初看想法

第一眼看到這個題目的資料範圍,顯然不是用暴力求解,先試試20%資料

20%資料

20%資料顯然可以通過列舉n嘛,把n枚舉出來再看看能否切掉k道題目就可以了。等等……列舉n?

100%資料

既然要列舉n,那完全可以用二分來列舉。這不就是一題二分答案嘛,只不過要求一個最大值一個最小值,兩次二分就能解決了。

code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,k;
ll a[100000+10];
ll pd(ll x){
    ll sum=0,t=0;
    for(int i=1;i<=n;i++){
        sum+=a[i];
        if(sum<0) sum=0;
        if(sum>=x) t++,sum=0;
    }
    return t;
}
int main(){
    cin>>n>>k;
    for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
    ll left=1,right=1e14;
    ll minans=-1,maxans=-1;
    while(left<=right){
        ll mid=(left+right)/2;
        ll d=pd(mid);
        if(d==k) minans=mid,right=mid-1;
        else if(d<k) right=mid-1;
        else left=mid+1;
    }
    left=1,right=1e14;
    while(left<=right){
        ll mid=(left+right)/2;
        ll d=pd(mid);
        if(d==k) maxans=mid,left=mid+1;
        else if(d<k) right=mid-1;
        else left=mid+1;
    }
    if(minans==-1&&maxans==-1) cout<<-1;
    else
    cout<<minans<<' '<<maxans;
}