7-3 位运算
默认理解十进制数和二进制数的转换。
三种位运算符&
,|
,^
- 对于&,只有1&1为1,其余都为0。
- 对于|,只有0|0为0,其余都为1。
- 对于^,相同为0,不同为1,比如1^1=0,1^0=1。
分析我们要达成的三种效果
- 因为1&0=0,0&0=0,所以对要变的第k位&0可以达到置0的效果;对于不需要变的位$1:1$1=1,0$1=0。
- 因为0|1=1,1|1=1,所以对要变的第k位|1可以达到置1的效果;对于不需要变的位|0:0|0=0,1|0=1。
- 因为 0^1=1 1^1=0,所以只要把要变的第k位^1即可达到取反的效果;对于不需要变的位^0:0^0=0,1^0=1。
#include<stdio.h>
int main(){
//1&0=0,0&0=0,所以&0可以置0,1&1=1,0%1=0
//1|1=1,0|1=1,所以|1可以置1,0|0=0,1|0=1
//1^1=0,0^1=1,所以^1可以取反,1^0=1,0^0=0
int x;
scanf("%d",&x);
int ord,k;
int tmp,rev;//tmp临时变量,rev作用的数
while(scanf("%d %d",&ord,&k)!=EOF){
switch(ord){
case 1://置0
//k=2,11111011
//1=00000001 1<<2=00000100
//00000100^11111111(-1)=11111011
tmp = -1;
rev = 1;
rev <<= k;
rev ^= tmp;
x &= rev;
break;
case 2://置1
//k=2 00000100
rev = 1;
rev <<= k;
x |= rev;
break;
case 3:
//k=2 00000100
rev = 1;
rev <<= k;
x ^= rev;
break;
default:
break;
}
}
printf("%d",x);
}
过程中有同学分享取反的位运算符~
,表扬!
x=x&~(1<<k)//置0
x=x|(1<<k)//置1
x=x^(1<<k)//取反
7-2 二分法求多项式单根
上一节拓展上机课讲完后才知道很多同学不清楚全局变量,这里补充一下:
- 定义在函数内部的变量称为局部变量(Local Variable),它的作用域仅限于函数内部, 离开该函数后就是无效的,再使用就会报错。
- (这一小点涉及函数的知识,未学习函数的同学可先跳过) 形参变量、在函数体内定义的变量都是局部变量。实参给形参传值的过程也就是给局部变量赋值的过程。
- 在所有函数外部定义的变量称为全局变量(Global Variable),它的作用域默认是整个程序。
- 当全局变量和局部变量同名时,在局部范围内全局变量被“屏蔽”,不再起作用。或者说,变量的使用遵循就近原则,如果在当前作用域中存在同名变量,就不会向更大的作用域中去寻找变量。
接着说一下二分的思想:
- 二分就是一分为二。简单来说二分就是在一个序列中,通过不断的二分,进而不断地缩小范围去寻找满足我们条件的解。
- 有兴趣的同学可以了解学习一下二分查找。
最后说一下本题的思路:
- 初等数学中我们学习过函数,对于一个函数f(x),当出现f(x0)=0,即x0为函数f(x)的一个根,当然这个题目也有说明。且题目保证多项式在给定区间内存在唯一单根。
- 也就是说这道题就是让我们在给定的区间[l,r]中找到一个x0,满足f(x0)=0。
- 所以我们将区间一分为二, m i d = l + r 2 mid=\frac{l+r}{2} mid=2l+r。判断一下mid是不是我们要找的根,如果不是,就对根所在的区间进行缩小。
- 根据题目给出的:
- 如果 f ( ( a + b ) / 2 ) 与 f ( a ) 同 号 , 则 说 明 根 在 区 间 [ ( a + b ) 2 , b ] f((a+b)/2)与f(a)同号,则说明根在区间[\frac{(a+b)}{2},b] f((a+b)/2)与f(a)同号,则说明根在区间[2(a+b),b]
- 如果 f ( ( a + b ) / 2 ) 与 f ( b ) 同 号 , 则 说 明 根 在 区 间 [ a , ( a + b ) 2 ] f((a+b)/2)与f(b)同号,则说明根在区间[a,\frac{(a+b)}{2}] f((a+b)/2)与f(b)同号,则说明根在区间[a,2(a+b)]
~~~~~ 确定根所在的新区间(缩小了一半)
- 重复以上步骤直到找到根。
- (特判)这题还要注意一下题目说的:
精确到小数点后2位和检查区间长度,如果小于给定阈值,则停止
#include<stdio.h>
double a3, a2, a1, a0;
double func(double x){//计算f(x)
return a3*x*x*x+a2*x*x+a1*x+a0;
}
int main(){
//区间范围大于等于0.01的时候要取精确值,小于0.01的时候可以取粗略值(a+b)/2
scanf("%lf %lf %lf %lf",&a3, &a2, &a1, &a0);
double l, r;
scanf("%lf %lf",&l,&r);//输入区间
while(r-l>=0.01){
double mid = (l+r)/2;
//计算精确根
if(!func(mid)) {
printf("%.2f",mid);
break;
}
else if(func(l)*func(mid)<0)
r = mid;
else l = mid;
}
if(r-l<0.01) printf("%.2f",(l+r)/2);
return 0;
}