• 【bzoj4590】[Shoi2015]自动刷题机 二分


    题目描述

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

    输入

    第一行两个整数 l,k,表示刷题机的日志一共有 l 行,一共了切了 k 题。
    第二行 l 个整数,x1…xl。xi>=0表示写了 xi 行代码。xi<0 表示删除了这道题的 -xi 行代码。
    1<=l,k<=100000,|xi|<=10^9

    输出

    输出两个数 a,b。分别代表 n 可能的最小值和最大值。如果不存在这样的 n 则输出 -1 。

    样例输入

    4 2
    2
    5
    -3
    9

    样例输出

    3 7


    题解

    二分

    显然随着 ans(n) 的增加,答案单调不增长。。。于是二分。。。没了。。。

    二分答案,直接模拟判断能否满足条件。

    求最小值时二分最小的ans,使得结果小于等于k;求最大值时二分最大的ans,使得结果大于等于k。

    注意二分出来结果以后需要代入检验一下结果是否等于k,因为求的是结果小于等于k的,可能取不到k。

    时间复杂度$O(nlog a)$

    #include <cstdio>
    typedef long long ll;
    ll a[100010];
    int n;
    int solve(ll mid)
    {
    	int i , ans = 0;
    	ll now = 0;
    	for(i = 1 ; i <= n ; i ++ )
    	{
    		now += a[i];
    		if(now < 0) now = 0;
    		if(now >= mid) now = 0 , ans ++ ;
    	}
    	return ans;
    }
    int main()
    {
    	int i , m;
    	ll l , r , mid , ans;
    	scanf("%d%d" , &n , &m);
    	for(i = 1 ; i <= n ; i ++ ) scanf("%lld" , &a[i]);
    	l = 1 , r = 1000000000000000ll , ans = -1;
    	while(l <= r)
    	{
    		mid = (l + r) >> 1;
    		if(solve(mid) <= m) ans = mid , r = mid - 1;
    		else l = mid + 1;
    	}
    	if(ans == -1 || solve(ans) != m) puts("-1");
    	else
    	{
    		printf("%lld " , ans);
    		l = 1 , r = 1000000000000000ll , ans = -1;
    		while(l <= r)
    		{
    			mid = (l + r) >> 1;
    			if(solve(mid) >= m) ans = mid , l = mid + 1;
    			else r = mid - 1;
    		}
    		printf("%lld
    " , ans);
    	}
    	return 0;
    }
    

     

  • 相关阅读:
    Excel 用row()函数 在Excel中自动添加序号,
    sql server数据导入
    Excel导入sq server后数据列以科学计数法显示
    left join 和 left outer join 的区别
    多点求值与暴力插值
    生成函数

    洲阁筛 学习笔记
    「NOI2017」游戏 解题报告
    CF 1045 H. Self-exploration 解题报告
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7762552.html
Copyright © 2020-2023  润新知