2118: 签到题(二分+差分)

2118: 签到题
时间限制: 1 Sec 内存限制: 128 MB
提交: 54 解决: 22
[提交] [状态] [讨论版] [命题人:admin]
题目描述

作为acm集训队一员的你,有一天拿到了你的历史训练时长记录表。你当然是想让你的训练时长看起来好看一些,所以你想调整这份记录表,使得训练时长最少的一天的时间在所有可能的调整方案中最大。你还有m分钟就梦醒了,时间紧迫,你每一分钟可以使得连续的w天时长记录多一个单位时间。注意,在梦中,你不需要考虑一天有多少的时间限制。 输出经过你的调整,最小的时长。(睡醒前的答案)

输入

多组数据,第一行为一个整数T,表示数据组数(T<=10) 接下来每组数据,开头为n,m,w(1<=w , n<=100000, 0<=m <= 1000000),表示有记录的历史训练天数 接下来一行n个数,表示这一天你的签到时长t(0<=t<=1000000)

输出

输出T行,每行代表一组的答案。

样例输入

1
3 2 1
2 1 2

样例输出

2

二分答案,差分检查。

#include
#define fi first
#define se second
#define log2(a) log(n)/log(2)
#define show(a) cout<
#define show2(a,b) cout<
#define show3(a,b,c) cout<
#define tim printf("Time cost : %lf s\n",(double)clock()/CLOCKS_PER_SEC);
using namespace std;
 
typedef long long ll;
typedef pair<ll, ll> P;
typedef pair<P, ll> LP;
const ll inf = 0x3f3f3f3f;
const int N = 2e5+10;
const ll mod = 1e12;
const ll p=1e6;
const int base=131;
const double pi=acos(-1);
 
int a[N],n,rm,w,m;
int num[N];
bool check(int x)
{
    for(int i=1;i<=n;i++) num[i]=0;
    int t;
    m=rm;
    for(int i=1;i<=n;i++)
    {
        num[i]+=num[i-1];
        if(num[i]+a[i]<x)
        {
            t=x-a[i]-num[i];
            m-=t;
            num[i]+=t;
            num[i+w]-=t;
        }
    }
    return m>=0 ? 1 : 0;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%d",&n,&rm,&w);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        int l=0,r=2000001,ans;
        while(l<=r)
        {
            int mid=l+r>>1;
            if(check(mid))
            {
                ans=mid;
                l=mid+1;
            }
            else r=mid-1;
        }
        printf("%d\n",ans);
    }
}

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