zoukankan      html  css  js  c++  java
  • luoguP4343自动刷题机(二分标准题)

    https://www.luogu.org/problem/P4343
    参考博客:https://www.luogu.org/blog/ofnoname/solution-p4343

    这真是一语点醒梦中人啊! 其实我们只需要掌握好一种二分答案的正确写法就行了,不用非要是标准的(看不懂没关系, 说给自己听的)

    以下为那位博主的分析,我觉得特别好

    容易发现,对于给定的序列,n越大能过的题是越少的所以可以二分来求刚好过k道题左右边界

    若mid大于k,即做得太多了,就将l右移。

    若mid小于k,即做得太少了,就将r左移。

    求左边界,需要在mid等于k时将r左移,求右边界时则需将l右移。这个很好理解。
    (这就是我们在哪写ans = mid的依据了)

    印象里二分写法极多,但现在普遍应用 l<=r, l=mid+1, r=mid-1这个版本了,虽然要多记录一个ans,但是却在单调增单调时都能工作,并且可以轻松应对无解的情况。

    注意这种写法l应设为1,r设为无穷大即可。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    
    int k, l;
    long long a[100000+9];
    
    long long check(long long n) {
    	long long sum = 0, num = 0;
    	for(int i = 1; i <= l; i++) {
    		sum += a[i];
    		sum = max(sum, (long long)0);
    		if(sum >= n) {num++, sum = 0;}
    	}
    	return num;
    }
    
    int main() {
    	scanf("%d%d",&l, &k);
    	for(int i = 1; i <= l; i++) scanf("%lld", &a[i]);
    	long long l = 1, r = 1e18, mid, mn = -1, mx = -1;// l 设为1, r为INF(真正的INF 
    	while(l <= r) {
    		mid = (l+r)>>1;
    		if(check(mid) <= k) {
    			r = mid - 1;
    			if(check(mid) == k) mn = mid;//找最小值->需要在合法的时候把r左移,所以在更新r的地方写‘=’ 
    		} else l = mid + 1;
    	}
    	l = 1, r = 1e18;
    	while(l <= r) {
    		mid = (l+r)>>1;
    		if(check(mid) >= k) {
    			l = mid + 1;
    			if(check(mid) == k) mx = mid;//找最大值->需要在合法的时候把l右移, 所以... **让mx越来越大**
    		}else r = mid - 1;
    	}
    	if(mn == -1) printf("-1");//判断不合法情况 
    	else printf("%lld %lld", mn, mx);
    }
    
  • 相关阅读:
    Java-16 常用包装类
    Java-15 String类
    flask实现web端微信登录
    Flask-excel导出数据
    Java-14 单例模式
    Java-13 接口
    Java-12 抽象类
    结对项目:一个自动生成小学四则运算题目的命令行程序(c++)
    软工作业:第一次个人项目作业
    操作系统笔记一:操作系统引论
  • 原文地址:https://www.cnblogs.com/tyner/p/11289044.html
Copyright © 2011-2022 走看看