二分、三分、01分数规划 【第I弹】

目录

一、二分

1.对不同板子的理解

例题一:

超级经典二分题!!!Drying !


一、二分

1.对不同板子的理解

【听说二分很容易写歪,细节要注意,接下来的几种写法,建议是选中一个自己熟悉的就一直只写这个,免得写混,不过还是要好好理解】

 要避免“死循环”的出现,就是要让每一次的执行都有所改变,而不是判断之后相当于什么也没做,具体到代码就是 l 和 r 要移动,那为什么会死循环呢?因为我们的 mid = ( l + r )/2是“整除”啊,是“向下取整”,当 r==l+1 时,mid 会等于其中较小的那一个,也就是 l ,这时候如果右边的代码也写成  mid = ( l + r )/2 ,那么会在 l = mid 这里进入死循环(把 l 赋值为 l ,你干了个啥.)【可以拿数列 3 3 3 做下模拟】关于最终答案:找等号嘛,最后一次执行的mid就是x的下标啦,然后左边的就是 r ,右边的就是 l.

再来看一类写法:直接舍弃 mid ,不考虑那么多,每次 l = mid + 1 , r = mid - 1 , 那么区间就一定是在缩小的:

注意啦!这里while的条件里要等号

 那,我们最终答案写什么,看等号,对于上图左边的代码,if ( a[mid]>= x) r = mid - 1 ;最终 mid 是答案 所以 我们输出的就是 r + 1, 或者可以看下面那一句,a[mid] < x 时, l = mid +1 ,这里最后一次的mid 小于 x ,那就是比x小1,所以答案也是 l , 右边就是 l - 1 ,或者 r

还有就是,(l+r)有一种更安全的写法来防止溢出的:l + (r-l)/2 ;

 lower_bound是找大于等于x的第一个数的位置,upper_bound可用来找大于x的第一个数,记得减去数组名(因为返回的是迭代器(类似指针),减去数组名(首地址)就得到下标了)。。

【上面  就算排序下标从1开始,后面也不要多减一...因为你减的是地址得到一个你现在的下标,本来就是从多一的开始了,自然没必要减啊。。】

例题一:

A-[USACO 2009 Dec S]Music Notes_

题意:牛依次敲(奏)n个音符,给出每个音符分别要(连续)弹奏多长时间,Q次询问,每次询问给个T,问T~T+1时间牛牛们要敲哪个音。

思路:一个前缀和,然后标准二分思路,都不用自己写了,用现成函数就好。

AC代码:

#include<iostream>
#include<algorithm>
using namespace std;
const int M=5e4+6;
int n,q,a[M];
int main(){
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	cin>>n>>q;
	int i,x,t;
	for(i=1;i<=n;i++){
		cin>>x;
		a[i]=a[i-1]+x;
	}
	while(q--){
		cin>>t;
		cout<<upper_bound(a+1,a+1+n,t)-a<<'\n';
	}
	return 0;
}

超级经典二分题!!!Drying !

Drying - POJ 3104 - Virtual Judge (vjudge.net)

题意:有 n 件衣服,每件衣服含有一定水分,有自然晾干和拿吹风机吹干两种方式,晾干是每分钟减少一单元水,吹风机是每分钟使其减少 k 份水(这一分钟只能吹一件,不能换另一件衣服吹,衣服水分变为0后不会有变化)问最少多少分钟能把衣服全部弄干。

思路:这题满足单调性,即可二分结果,假设x时间为答案,那么比答案大的(判断的是"mid"时间),计算出的要花的时间就会比你预想的时间mid 少(即有时间剩余,所以我们这个答案大了,就该缩小,区间右边界左移,反之亦然)

虽然说这里的k是包含了自然风干的水分的(即这段时间干的就是k不是k+1)但千万注意这里除的是 (k-1),www为什么呢,咱就是说凡事推推公式 好处多多 一目了然,不要想当然。->设总时间为x , t 为吹风机时间,kt + (x-t) >=a[i]  , kt-t >= a[i]-x , (k-1)t >=a[i]

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int M=1e5+6;
ll n, k, a[M], sum;
bool check(int x){
	int i=upper_bound(a+1,a+1+n,x)-a;//找到第一个需要使用吹风机的位置 
	sum=0;
	for(;i<=n;i++)sum+=(a[i]-x+k-2)/(k-1);//加个k-2是为了向上取整,也可以用ceil函数 
	return sum<=x?1:0;//计算的时间比设定的小,就返回真 
}
int main(){
	scanf("%lld",&n);//POJ卡cin.... 
	for(int i=1;i<=n;i++)scanf("%lld",a+i);
	sort(a+1,a+1+n);
	scanf("%lld",&k);
	if(k==1){printf("%lld",a[n]);return 0;}
	int l=1, r=1e9;
	while(l<r){//二分板子之一,不熟悉就看看上文吧 
		int mid=l+r>>1;
		if(check(mid))r=mid;
		else l=mid+1;
	}
	printf("%d",r);
	return 0;
}

<think>好的,用户想用C语言筛选出80分以上的同学分数。我需要先理解他的需求。他可能有一个分数列表,需要找出所有大于等于80分的成绩,并输出这些分数。可能需要考虑如何存储这些分数,比如数组,然后遍历数组进行比较。 首先,我需要确定用户的数据输入方式。是手动输入还是从文件读取?这里可能先以手动输入为例,因为更基础。然后,处理流程大致是:输入分数,存储到数组,遍历数组检查每个元素是否>=80,符合条件的输出。 接下来要考虑数组的大小。可能需要用户先输入学生人数,然后依次输入每个分数。或者使用动态数组,但C语言中动态数组可能需要malloc,对于初学者来说可能有点复杂,所以先固定一个最大人数,比如100,或者让用户先输入人数。 然后循环输入分数,存储到数组。之后遍历数组,用if语句判断是否大于等于80,满足的话打印出来。 需要注意的部分包括:输入验证,比如分数是否在0-100之间,但用户可能暂时不需要这个,先专注于主要功能。还有边界情况,比如所有分数都低于80,这时候需要提示没有符合条件的学生。 可能的代码结构: 1. 声明变量,如数组、人数、循环计数器。 2. 获取学生人数。 3. 循环输入每个学生的分数,存入数组。 4. 遍历数组,比较每个分数,输出符合条件的。 5. 如果没有符合条件的,给出提示。 然后测试一下代码是否正确。比如输入5个分数:75, 80, 90, 85, 78,应该输出80,90,85。 可能的问题:数组越界,输入非数字导致错误。但用户可能只需要基础实现,暂时不考虑异常处理。 最后,整理代码,确保语法正确,注释清晰,方便用户理解。</think>下面用C语言实现筛选80分以上同学分数的分步教学: 一、算法思路 1. 使用数组存储学生成绩 2. 遍历数组元素 3. 使用if语句判断分数是否≥80 4. 输出符合条件的结果 二、代码实现(带详细注释) ```c #include <stdio.h> #define MAX_STUDENTS 100 // 最大学生人数 int main() { int scores[MAX_STUDENTS]; // 成绩存储数组 int count; // 实际学生人数 int hasHighScore = 0; // 标记是否存在高分 // 步骤1:输入学生成绩 printf("请输入学生人数(不超过%d):", MAX_STUDENTS); scanf("%d", &count); printf("请输入%d个学生分数(0-100):\n", count); for(int i = 0; i < count; i++) { scanf("%d", &scores[i]); } // 步骤2:筛选并输出结果 printf("\n80分以上的成绩:\n"); for(int i = 0; i < count; i++) { if(scores[i] >= 80) { printf("学生%d:%d分\n", i+1, scores[i]); hasHighScore = 1; } } // 处理无高分情况 if(!hasHighScore) { printf("没有80分以上的成绩\n"); } return 0; } ``` 三、代码说明 1. 输入阶段: - 使用`#define`定义最大容量,方便修改 - 通过循环结构实现批量数据输入 - 限制输入成绩范围0-100(符合实际场景) 2. 处理阶段: - 双重循环设计:输入循环+筛选循环 - 使用布尔标记`hasHighScore`处理特殊情况 - 格式化输出包含学生序号和分数 3. 扩展性: - 修改`#define MAX_STUDENTS`可调整容量 - 调整if条件中的80可改变筛选标准 四、执行示例 ``` 请输入学生人数(不超过100):5 请输入5个学生分数(0-100): 75 80 90 85 78 80分以上的成绩: 学生2:80分 学生3:90分 学生4:85分 ``` 五、注意事项 1. 输入人数时不要超过MAX_STUDENTS的值 2. 分数应为0-100的整数 3. 程序会明确提示没有高分的情况 4. 学生编号从1开始计数,更符合日常习惯 这个程序可以实现基本的筛选功能,如需处理更复杂需求(如文件读写、异常处理等),可以在本程序基础上进行扩展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值