基本运算与位运算
基本运算与位运算
算术运算(加、减、乘、除、整除、求余);关系运算;逻辑运算(&&、||、!);变量自增与自减;三目运算;位运算(&、|、~、^、<<、>>)。
概念
运算符定义表达式如何求值:算术运算注意整数除法截断与 % 符号;关系运算得到 bool;逻辑运算有短路(&& 左侧假则不算右侧)。自增自减前缀与后缀在表达式中的值不同。位运算按二进制位操作,与逻辑运算完全不同——初赛既考 &|^ 也考「逻辑与/按位与」概念混淆。三目 ?: 是精简分支。本叶子覆盖所有运算符语义,与 cspj.cpp.mathlib(调用库函数)和 cspj.cpp.branch(用运算结果控制流程)相邻。2022 复赛「逻辑表达式」题(cspj-r2-2022 编程 3)还把 &/| 优先级与短路计数推到了实现层面。
CSP-J 常考
cspj-r1-2022第 6、18–21 题:单选与阅读,位运算、逻辑短路、自增表达式混合求值。cspj-r1-2019第 2 题:单选题,两个二进制数按位逻辑与(注意与「逻辑与」题干区分)。cspj-r1-2021第 18–19、26、37 题:阅读判断与完善程序,考查%、&&/||或比较链。cspj-r1-2025第 2、7 题:单选题,表达式优先级或位运算结果。cspj-r2-2022编程第 3 题:实现带&、|、!的表达式求值并统计短路次数。
int a = 5, b = 2;
cout << (a / b) << " " << (a % b) << endl; // 2 1
cout << ((a & 1) ? "odd" : "even") << endl;
int i = 0;
cout << i++ << " " << ++i << endl; // 0 2
易错点
i++与++i在同一表达式里出现(如a[i++] = i++)求值顺序未定义,阅读题若出现应标记行为不确定或按题面假设逐行推。- 逻辑与
&&与按位与&:前者短路,后者对每一位运算;2019 第 2 题即考此区分。 - 完善程序空位在条件位置,
=与==、|与||选项并存时要先看空位是否在if/while括号内。
二进制数 11 1011 1001 0111 和 01 0110 1110 1011 进行逻辑与运算的结果是()。
原文保真说明:来源改写 1 处(照原卷保留,未作修改)
来源题面被改写措辞改写题干
原卷作
逻辑与,常规写法应为逻辑与洛谷抓取件已将题干改为「按位与」并附 editor_correction;对照 pages/pg-01.png 第 2 题原文为「逻辑与」,已从来源改写恢复。
已按官方原件恢复:现为原卷原文
整组作答后提交批改,成绩计入掌握度 · 已答 0/1
1.(矩阵变幻)有一个奇幻的矩阵,在不停的变幻,其变幻方式为:
数字 0 变成矩阵
0 0
0 1
数字 1 变成矩阵
1 1
1 0
最初该矩阵只有一个元素 0,变幻 n 次后,矩阵会变成什么样?
例如,矩阵最初为:[0];
矩阵变幻 1 次后:
0 0
0 1
矩阵变幻 2 次后:
0 0 0 0
0 1 0 1
0 0 1 1
0 1 1 0
输入一行一个不超过 10 的正整数 n。输出变幻 n 次后的矩阵。
试补全程序。
提示:
<< 表示二进制左移运算符,例如 (11)2 << 2=(1100)2;
而 ^ 表示二进制异或运算符,它将两个参与运算的数中的每个对应的二进制位—进行比较,若两个二进制位相同,则运算结果的对应二进制位为 0 ,反之为 1。
#include <cstdio>
using namespace std;
int n;
const int max_size = 1 << 10;
int res[max_size][max_size];
void recursive(int x, int y, int n, int t) {
if (n == 0) {
res[x][y] = ①;
return;
}
int step = 1 << (n - 1);
recursive(②, n - 1, t);
recursive(x, y + step, n - 1, t);
recursive(x + step, y, n - 1, t);
recursive(③, n - 1, !t);
}
int main() {
scanf("%d", &n);
recursive(0, 0, ④);
int size = ⑤;
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++)
printf("%d", res[i][j]);
puts("");
}
return 0;
}
#include <cstdio>2using namespace std;3int n;4const int max_size = 1 << 10;56int res[max_size][max_size];78void recursive(int x, int y, int n, int t) {9 if (n == 0) {10 res[x][y] = ①;11 return;12 }13 int step = 1 << (n - 1);14 recursive(②, n - 1, t);15 recursive(x, y + step, n - 1, t);16 recursive(x + step, y, n - 1, t);17 recursive(③, n - 1, !t);18}1920int main() {21 scanf("%d", &n);22 recursive(0, 0, ④);23 int size = ⑤;24 for (int i = 0; i < size; i++) {25 for (int j = 0; j < size; j++)26 printf("%d", res[i][j]);27 puts("");28 }29 return 0;30}- 38(⑤)单选空位 ⑤3 分
⑤处应填()
设 x=true,y=true,z=false,以下逻辑运算表达式值为真的是( )。
整组作答后提交批改,成绩计入掌握度 · 已答 0/1
原卷作答说明:判断题正确填 √,错误填 ×
#include <iostream>2using namespace std;34int n;5int a[1000];67int f(int x)8{9 int ret = 0;10 for (; x; x &= x - 1) ret++;11 return ret;12}1314int g(int x)15{16 return x & -x;17}1819int main()20{21 cin >> n;22 for (int i = 0; i < n; i++) cin >> a[i];23 for (int i = 0; i < n; i++)24 cout << f(a[i]) + g(a[i]) << ' ';25 cout << endl;26 return 0;27}- 18判断1.5 分
当输入为
5 2 11 9 16 10时,输出为3 4 3 17 5。( )
整组作答后提交批改,成绩计入掌握度 · 已答 0/1
原卷作答说明:判断题正确填 √,错误填 ×
#include <iostream>2using namespace std;34int n;5int a[1000];67int f(int x)8{9 int ret = 0;10 for (; x; x &= x - 1) ret++;11 return ret;12}1314int g(int x)15{16 return x & -x;17}1819int main()20{21 cin >> n;22 for (int i = 0; i < n; i++) cin >> a[i];23 for (int i = 0; i < n; i++)24 cout << f(a[i]) + g(a[i]) << ' ';25 cout << endl;26 return 0;27}- 19判断1.5 分
当输入为
1 511998时,输出为18。( )
整组作答后提交批改,成绩计入掌握度 · 已答 0/1
#include <iostream>2#include <string>3using namespace std;45char base[64];6char table[256];78void init()9{10 for (int i = 0; i < 26; i++) base[i] = 'A' + i;11 for (int i = 0; i < 26; i++) base[26 + i] = 'a' + i;12 for (int i = 0; i < 10; i++) base[52 + i] = '0' + i;13 base[62] = '+', base[63] = '/';1415 for (int i = 0; i < 256; i++) table[i] = 0xff;16 for (int i = 0; i < 64; i++) table[base[i]] = i;17 table['='] = 0;18}1920string decode(string str)21{22 string ret;23 int i;24 for (i = 0; i < str.size(); i += 4) {25 ret += table[str[i]] << 2 | table[str[i + 1]] >> 4;26 if (str[i + 2] != '=')27 ret += (table[str[i + 1]] & 0x0f) << 4 | table[str[i + 2]] >> 2;28 if (str[i + 3] != '=')29 ret += table[str[i + 2]] << 6 | table[str[i + 3]];30 }31 return ret;32}3334int main()35{36 init();37 cout << int(table[0]) << endl;3839 string str;40 cin >> str;41 cout << decode(str) << endl;42 return 0;43}- 26单选3 分
当输入为 Y3Nx 时,输出的第二行为()。
整组作答后提交批改,成绩计入掌握度 · 已答 0/1
(1)(Josephus 问题) 有 n 个人围成一个圈,依次标号 0 至 n−1。从 0 号开始,依次 0,1,0,1,… 交替报数,报到 1 的人会离开,直至圈中只剩下一个人。求最后剩下人的编号。
试补全模拟程序。
#include <iostream>23using namespace std;45const int MAXN = 1000000;6int F[MAXN];78int main() {9 int n;10 cin >> n;11 int i = 0, p = 0, c = 0;12 while (①) {13 if (F[i] == 0) {14 if (②) {15 F[i] = 1;16 ③;17 }18 ④;19 }20 ⑤;21 }22 int ans = -1;23 for (i = 0; i < n; i++)24 if (F[i] == 0)25 ans = i;26 cout << ans << endl;27 return 0;28}- 37(④)单选空位 ④3 分
④处应填( )
A.i++
B.i = (i + 1) % n
C.c++
D.p ^= 1
对表达式 a+(b-c)*d 的前缀表达式为( ),其中 +、-、* 是运算符。
整组作答后提交批改,成绩计入掌握度 · 已答 0/1
01 #include <iostream>202303 using namespace std;404505 int main()606 {707 unsigned short x, y;808 cin >> x >> y;909 x = (x | x << 2)& 0x33;1010 x = (x | x << 1)& 0x55;1111 y = (y | y << 2)& 0x33;1212 y = (y | y << 1)& 0x55;1313 unsigned short z = x | y << 1;1414 cout << z << endl;1515 return 0;1616 }- 18判断1.5 分
程序总是输出一个整数“0”。
整组作答后提交批改,成绩计入掌握度 · 已答 0/1
01 #include <iostream>202303 using namespace std;404505 int main()606 {707 unsigned short x, y;808 cin >> x >> y;909 x = (x | x << 2)& 0x33;1010 x = (x | x << 1)& 0x55;1111 y = (y | y << 2)& 0x33;1212 y = (y | y << 1)& 0x55;1313 unsigned short z = x | y << 1;1414 cout << z << endl;1515 return 0;1616 }- 19判断1.5 分
当输入为
2 2时,输出为10。
整组作答后提交批改,成绩计入掌握度 · 已答 0/1
01 #include <iostream>202303 using namespace std;404505 int main()606 {707 unsigned short x, y;808 cin >> x >> y;909 x = (x | x << 2)& 0x33;1010 x = (x | x << 1)& 0x55;1111 y = (y | y << 2)& 0x33;1212 y = (y | y << 1)& 0x55;1313 unsigned short z = x | y << 1;1414 cout << z << endl;1515 return 0;1616 }- 20判断1.5 分
当输入为
2 2时,输出为59。
整组作答后提交批改,成绩计入掌握度 · 已答 0/1
01 #include <iostream>202303 using namespace std;404505 int main()606 {707 unsigned short x, y;808 cin >> x >> y;909 x = (x | x << 2)& 0x33;1010 x = (x | x << 1)& 0x55;1111 y = (y | y << 2)& 0x33;1212 y = (y | y << 1)& 0x55;1313 unsigned short z = x | y << 1;1414 cout << z << endl;1515 return 0;1616 }- 21单选3 分
单选题
- 当输入为
13 8时,输出为( )。
- 当输入为
逻辑表达式
C++时间 1 s内存 512 MB 文件 IO:expr.in → expr.out
逻辑表达式是计算机科学中的重要概念和工具,包含逻辑值、逻辑运算、逻辑运算优先级等内容。
在一个逻辑表达式中,元素的值只有两种可能:0(表示假)和 1(表示真)。元素之间有多种可能的逻辑运算,本题中只需考虑如下两种:“与”(符号为 &)和“或”(符号为 |)。其运算规则如下:
0&0=0&1=1&0=0,1&1=1;
0∣0=0,0∣1=1∣0=1∣1=1。
在一个逻辑表达式中还可能有括号。规定在运算时,括号内的部分先运算;两种运算并列时,& 运算优先于 | 运算;同种运算并列时,从左向右运算。
比如,表达式 0|1&0 的运算顺序等同于 0|(1&0);表达式 0&1&0|1 的运算顺序等同于 ((0&1)&0)|1。
此外,在 C++ 等语言的有些编译器中,对逻辑表达式的计算会采用一种“短路”的策略:在形如 a&b 的逻辑表达式中,会先计算 a 部分的值,如果 a=0,那么整个逻辑表达式的值就一定为 0,故无需再计算 b 部分的值;同理,在形如 a|b 的逻辑表达式中,会先计算 a 部分的值,如果 a=1,那么整个逻辑表达式的值就一定为 1,无需再计算 b 部分的值。
现在给你一个逻辑表达式,你需要计算出它的值,并且统计出在计算过程中,两种类型的“短路”各出现了多少次。需要注意的是,如果某处“短路”包含在更外层被“短路”的部分内则不被统计,如表达式 1|(0&1) 中,尽管 0&1 是一处“短路”,但由于外层的 1|(0&1) 本身就是一处“短路”,无需再计算 0&1 部分的值,因此不应当把这里的 0&1 计入一处“短路”。
输入格式
从文件 expr.in 中读入数据。
输入共一行,一个非空字符串 s 表示待计算的逻辑表达式。
输出格式
输出到文件 expr.out 中。
输出共两行,第一行输出一个字符 0 或 1,表示这个逻辑表达式的值;第二行输出两个非负整数,分别表示计算上述逻辑表达式的过程中,形如 a&b 和 a|b 的“短路”各出现了多少次。
样例
0&(1|0)|(1|1|1&0)
1 1 2
该逻辑表达式的计算过程如下,每一行的注释表示上一行计算的过程:
0&(1|0)|(1|1|1&0)
=(0&(1|0))|((1|1)|(1&0)) //用括号标明计算顺序
=0|((1|1)|(1&0)) //先计算最左侧的 &,是一次形如 a&b 的“短路”
=0|(1|(1&0)) //再计算中间的 |,是一次形如 a|b 的“短路”
=0|1 //再计算中间的 |,是一次形如 a|b 的“短路”
=1
(0|1&0|1|1|(1|1))&(0&1&(1|0)|0|1|0)&0
0 2 3
数据范围
对于所有数据,1≤∣s∣≤106。保证 s 中仅含有字符 0、1、&、|、(、) 且是一个符合规范的逻辑表达式。保证输入字符串的开头、中间和结尾均无额外的空格。保证 s 中没有重复的括号嵌套(即没有形如 ((a)) 形式的子串,其中 a 是符合规范的逻辑表达式)。
| 测试点编号 | ∣s∣≤ | 特殊条件 |
|---|---|---|
| 1∼2 | 3 | 无 |
| 3∼4 | 5 | 无 |
| 5 | 2000 | 1 |
| 6 | 2000 | 2 |
| 7 | 2000 | 3 |
| 8∼10 | 2000 | 无 |
| 11∼12 | 106 | 1 |
| 13∼14 | 106 | 2 |
| 15∼17 | 106 | 3 |
| 18∼20 | 106 | 无 |
其中:
特殊性质 1 为:保证 s 中没有字符 &。
特殊性质 2 为:保证 s 中没有字符 |。
特殊性质 3 为:保证 s 中没有字符 ( 和 )。
【提示】
以下给出一个“符合规范的逻辑表达式”的形式化定义:
- 字符串
0和1是符合规范的; - 如果字符串
s是符合规范的,且s不是形如(t)的字符串(其中t是符合规范的),那么字符串(s)也是符合规范的; - 如果字符串
a和b均是符合规范的,那么字符串a&b、a|b均是符合规范的; - 所有符合规范的逻辑表达式均可由以上方法生成。
部分分
- 10 分
测试点 1,2:∣s∣≤3,无特殊条件。
- 10 分
测试点 3,4:∣s∣≤5,无特殊条件。
- 5 分
测试点 5:∣s∣≤2000,特殊条件 1。
- 5 分
测试点 6:∣s∣≤2000,特殊条件 2。
- 5 分
测试点 7:∣s∣≤2000,特殊条件 3。
- 15 分
测试点 8∼10:∣s∣≤2000,无特殊条件。
- 10 分
测试点 11,12:∣s∣≤106,特殊条件 1。
- 10 分
测试点 13,14:∣s∣≤106,特殊条件 2。
- 15 分
测试点 15∼17:∣s∣≤106,特殊条件 3。
- 15 分
测试点 18∼20:∣s∣≤106,无特殊条件。
你的代码(C++)
提交后由评测机编译运行,结果见下方76 B / 64 KB
判题结果
整组作答后提交批改,成绩计入掌握度 · 已答 0/1
#include<iostream>2#include<cmath>3using namespace std;45double f(double a,double b,double c){6 double s=(a+b+c)/2;7 return sqrt(s*(s-a)*(s-b)*(s-c));8}9int main(){10 cout.flags(ios::fixed);11 cout.precision(4);12 13 int a,b,c;14 cin>>a>>b>>c;15 cout<<f(a,b,c)<<endl;16 return 0;17}- 17判断2 分
(2分)将第7行中的
(s-b)*(s-c)改为(s-c)*(s-b)不会影响程序运行的结果( )
整组作答后提交批改,成绩计入掌握度 · 已答 0/1
第 1 题
(判断平方数) 问题:给定一个正整数 n,希望判断这个数是否为完全平方数,即存在一个正整数 x,使得 x 的平方为 n。
试补全程序。
#include<iostream>
#include<vector>
using namespace std;
bool isSquare(int num) {
int i = ___①___;
int bound = ___②___;
for (; i <= bound; ++i) {
if (___③___) {
return ___④___;
}
}
return___⑤___;
}
int main() {
int n;
cin >> n;
if (isSquare(n)) {
cout << n << " is a square number" << endl;
} else {
cout << n << " is not a square number" << endl;
}
return 0;
}
#include<iostream>2#include<vector>3using namespace std;45bool isSquare(int num) {6 int i = ___①___;7 int bound = ___②___;8 for (; i <= bound; ++i) {9 if (___③___) {10 return ___④___;11 }12 }13 return___⑤___;14}1516int main() {17 int n;18 cin >> n;19 if (isSquare(n)) {20 cout << n << " is a square number" << endl;21 } else {22 cout << n << " is not a square number" << endl;23 }24 return 0;25}- 35(③)单选空位 ③3 分
③ 处应填( )
在 C++ 中,执行 int x = 255; cout << (x & (x - 1)); 后,输出的结果是?
假设 a,b,c 都是布尔变量,逻辑表达式 (a && b) || (!c && a) 的值与下列哪个表达式不始终相等?