目录
1.A题(进制位数)
位运算符
第一期
问题描述
解析
第二期
解析
代码
2.B题(日期问题)
第一期
问题描述
解析
代码实现
执行结果
第二期
问题描述
解析
3.C题(数学问题)
第一期
问题描述
解析
代码实现
执行结果
第二期
问题描述
解析
4.D题(矩阵问题)
第一期
问题描述
解析
代码实现
第二期
问题描述
解析
5.E题(拆分问题)
第一期
问题描述
解析
第二期
问题描述
解析
总结
符号 | 描述 | 运算规则 |
& | 与 | 两个位都为1时,结果才为1 |
| | 或 | 两个位都为0时,结果才为0 |
^ | 异或 | 两个位相同为1,相异为0 |
~ | 取反 | 0变1,1变0 |
<< | 左移 | 各二进位全部左移若干位,高位丢弃,低位补0 |
>> | 右移 | 各二进位全部右移若干位,对无符号数,高位补0,有符号数,各编译器处理方法不一样,有的补符号位(算术右移),有的补0(逻辑右移) |
十进制整数 2 在十进制中是 1 位数,在二进制中对应 10 ,是 2 位数。
十进制整数 22 在十进制中是 2 位数,在二进制中对应 10110 ,是 5 位数。
请问十进制整数 2022 在二进制中是几位数?
根据常识2^10为1024,那么2^11就是2048,2048>2022,即2^10<2022<2^11。
由2<3<2^2,为两位数;2^4<22<2^5,为五位数可知2022的位数为10+1即11位。
答案:11位。
请找到一个大于 2022 的最小数,这个数转换成二进制之后,最低的 6 个二进制为全为 0 。
请将这个数的十进制形式作为答案提交。
2022联想到2048(100000000000),for循环从2023开始,找到那个大于 2022 的最小数结束,判断方法:对该整数进行六次右移如果每一次的&(与)1都不为1,即最低的 6 个二进制为全为 0,那么这个数就是那个大于 2022 的最小数。
答案:2048。
#include
using namespace std;
int main() {
int s;
for (int i = 2023;; i++) {
bool flag = false;
for (int k = 0; k < 6; k++) {
if (i >> k & 1) {
flag = true;
continue;
}
}
if (!flag) {
s = i;
break;
}
}
cout << s << endl;
return 0;
小蓝每周六、周日都晨跑,每月的 1、11、21、31 日也晨跑。其它时间不晨跑。
已知 2022 年 1 月 1 日是周六,请问小蓝整个 2022 年晨跑多少天?
由题意可知小蓝周末跑,日期位数为1的时候也跑。假设定义x为365天的某一天,那么小蓝周末跑的条件就是x%7==1为周六或x%7==1为周日,定义一个数组,每个元素代表着每个月份的日期,用枚举法判断日期是否为1、11、21、31 ,用count计算晨跑的天数,x随着循环加1,满足x%7==1或x%7==1或判断日期是否为1、11、21、31之一,count加1。
答案:138。
#include
#include
int main(int argc, char *argv[])
{
int x = 0, count = 0;
int month[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
for (int i = 1; i < 13; i++) {
for (int j = 1; j <= month[i]; j++) {
x++;
if (x % 7 == 1 || x % 7 == 2 || j == 1 || j == 11 || j == 21 || j == 31) {
count++;
}
}
}
printf("%d", count);
}
虽然月份是12个,但是数组定义为13个,把第一个赋值为0,使用时从第二个元素开始,也就是下标为1代表着一月,这样便于理解
我们计从 1949 年 10 月 1 日至 1949 年 10 月 2 日为经过了 1 天。请问从 1949 年 10 月 1 日至 2022 年 1 月 1 日经过了多少天?
分两段算,先计算1949 年 10 月 1 日到1950 年 1 月 1 日为31+30+31=92,在计算1950 年 1 月 1 日到2022 年 1 月 1 日,用for循环,判断是否为闰年,如果为闰年加366,不是闰年加365。最后两者相加即为答案。
答案:26390
代码
#include "stdio.h"
int main() {
int sum = 92;
for (int i = 1950; i < 2022; i++) {
if (i % 4 == 0 && i % 100 != 0 || i % 400 == 0) {
sum += 366;
} else {
sum += 365;
}
}
printf("%d", sum);
return 0;
}
小蓝特别喜欢调和级数 S(n)=1/1+1/2+1/3+...+1/n
请问,n 至少为多大时,S(n)>12 ?
直接暴力累加计算,需要注意的是结果涉及到了循环的++运算
- S>0 n=1
- S>1 n=2
- S>2 n=4
- S>3 n=11
- S>4 n=31
- S>5 n=83
- S>6 n=227
- S>7 n=616
- S>8 n=1674
- S>9 n=4550
- S>10 n=12367
- S>11 n=33617
- S>12 n=91380
答案:91380
#include
#include
int main(int argc, char *argv[])
{
double sum = 0;
int i;
for (i = 1; sum <= 12; i++) {
sum += 1.0 / i;
}
printf("%d", i - 1);
return 0;
}
切记,切记,切记,最后输出n的时候要减1,因为在最后一次循环的结尾i又加1,而不满足条件的是i加1之前的值
8518 是一个非常特殊的数,如果把这个数看成 16 进制数,它的值为 (8518)16=8*16*16*16+5*16*16+1*16+8=34072,而 34072 正好是 8518 的整数倍。9558 也是这样一个数,当看成 16 进制时是 38232。其实长度为 1 的数 0 到 9 都满足看成 16 进制后是自己的整数倍(1倍)。请问,除开长度为 1 的数,最小的满足这样条件的数是多少?
for循环从10开始往后枚举,直到找到满足条件的数结束,判断方法:现将该数转换为十六进制(对其求余每次除10从尾数求其位数,权重每循环一次乘以16,位数乘权重累加),最后在用这个数求余它本身10进制的数,如果为0,这满足,反之,继续循环。
答案:1038
代码
#include
using namespace std;
int main() {
int res;
for (int i = 10;; i++) {
int weight = 1;
int ans = 0, sum = 0;
int temp = i;
while (temp) {
sum = temp % 10;
ans += sum * weight;
weight *= 16;
temp /= 10;
}
if (ans % i == 0) {
res = i;
break;
}
}
cout << res << endl;
return 0;
}
给定一个字母矩阵,如果矩阵中的某个位置不在四条边上,而且该位置上的字母小于其上下左右四个位置的字母,则称为一个山谷。
例如,对于如下矩阵
DDDDD
CADCE
FFFFA
共有两个山谷,位于第二行第二列和第四列。请注意第二行第三列和第三行第五列都不是山谷。
对于如下 3030 行 6060 列的字母矩阵,请问有多少个山谷?
PHQGHUMEAYLNLFDXFIRCVSCXGGBWKFNQDUXWFNFOZVSRTKJPREPGGXRPNRVY STMWCYSYYCQPEVIKEFFMZNIMKKASVWSRENZKYCXFXTLSGYPSFADPOOEFXZBC OEJUVPVABOYGPOEYLFPBNPLJVRVIPYAMYEHWQNQRQPMXUJJLOOVAOWUXWHMS NCBXCOKSFZKVATXDKNLYJYHFIXJSWNKKUFNUXXZRZBMNMGQOOKETLYHNKOAU GZQRCDDIUTEIOJWAYYZPVSCMPSAJLFVGUBFAAOVLZYLNTRKDCPWSRTESJWHD IZCOBZCNFWLQIJTVDWVXHRCBLDVGYLWGBUSBMBORXTLHCSMPXOHGMGNKEUFD XOTOGBGXPEYANFETCUKEPZSHKLJUGGGEKJDQZJENPEVQGXIEPJSRDZJAZUJL LCHHBFQMKIMWZOBIWYBXDUUNFSKSRSRTEKMQDCYZJEEUHMSRQCOZIJIPFION EEDDPSZRNAVYMMTATBDZQSOEMUVNPPPSUACBAZUXMHECTHLEGRPUNKDMBPPW EQTGJOPARMOWZDQYOXYTJBBHAWDYDCPRJBXPHOOHPKWQYUHRQZHNBNFUVQNQ QLRZJPXIOGVLIEXDZUZOSRKRUSVOJBRZMWZPOWKJILEFRAAMDIGPNPUUHGXP QNJWJMWAXXMNSNHHLQQRZUDLTFZOTCJTNZXUGLSDSMZCNOCKVFAJFRMXOTHO WKBJZWUCWLJFRIMPMYHCHZRIWKBARXBGFCBCEYHJUGIXWTBVTREHBBCPXIFB XVFBCGKCFQCKCOTZGKUBMJRMBSZTSSHFROEFWSJRXJHGUZYUPZWWEIQURPIX IQFLDUUVEOOWQCUDHNEFNJHAIMUCZFSKUIDUBURISWTBRECUYKABFCVKDZEZ TOIDUKUHJZEFCZZZBFKQDPQZIKFOBUCDHTHXDJGKJELRLPAXAMCEROSWITDP TPCCLIFKELJYTIHRCQAYBNEFXNXVGZEDYYHNGYCDRUDMPHMECKOTRWOSPOFG HFOZQVLQFXWWKMFXDYYGMDCASZSGOVSODKJGHCWMBMXRMHUYFYQGAJQKCKLZ NAYXQKQOYZWMYUBZAZCPKHKTKYDZIVCUYPURFMBISGEKYRGZVXDHPOAMVAFY RARXSVKHTQDIHERSIGBHZJZUJXMMYSPNARAEWKEGJCCVHHRJVBJTSQDJOOTG PKNFPFYCGFIEOWQRWWWPZSQMETOGEPSPXNVJIUPALYYNMKMNUVKLHSECDWRA CGFMZKGIPDFODKJMJQWIQPUOQHIMVFVUZWYVIJGFULLKJDUHSJAFBTLKMFQR MYJFJNHHSSQCTYDTEAMDCJBPRHTNEGYIWXGCJWLGRSMEAEARWTVJSJBAOIOJ LWHYPNVRUIHOSWKIFYGTYDHACWYHSGEWZMTGONZLTJHGAUHNIHREQGJFWKJS MTPJHAEFQZAAULDRCHJCCDYRFVVRIVUYEEGFIVDRCYGURQDREDAKUBNFGUPR OQYLOBCWQXKZMAUSJGMHCMHGDNMPHNQKAMHURKTRFFACLVGRZKKLDACLLTEO JOMONXRQYJZGINRNNZWACXXAEDRWUDXZRFUSEWJTBOXVYNFHKSTCENAUMNDD XFDMVZCAUTDCCKXAAYDZSXTTOBBGQNGVVPJGOJOGLMKXGBFCPYPCKQCHBDDZ WRXBZMQRLXVOBTWHXGINFGFRCCLMZNMJUGWWBSQFCIHUBSJOLLMSQSGHMCPH ELSOTFLBGSFNPCUZSRUPCHYNVZHCPQUGRIWNIQXDFJPWPXFBLKPNPEELFJMT
枚举法判断每个字符与该字符上下左右四个位置的字母的大小,如果该位置上的字母小于其上下左右四个位置的字母那么计数变量count++。
答案:276
#include
using namespace std;
int main() {
char str[30][60];
int count = 0;
for (int i = 0; i < 30; i++) {
for (int j = 0; j < 60; j++) {
// scanf("%c", &str[i][j]);
cin >> str[i][j];
}
}
printf("\n");
for (int i = 0; i < 30; i++) {
for (int j = 0; j < 60; j++) {
printf("%c", str[i][j]);
}
}
for (int i = 1; i < 29; i++) {
for (int j = 1; j < 59; j++) {
if (str[i - 1][j] > str[i][j] && str[i + 1][j] > str[i][j] && str[i][j - 1] > str[i][j] && str[i][j + 1] > str[i][j]) {
count++;
}
}
}
printf("%d", count);
return 0;
}
输入流cin无论什么情况下都会忽略tab、空格、回车等分隔符
scanf函数在除
scanf("%c",&char)
之外的所有情况都不会把回车符作为输入字符在输入缓存中读取,但scanf("%c",&char)
也不会读取tab、空格,而是把他们作为分隔符在输入缓存中忽略。
小蓝有一个 30 行 60 列的数字矩阵,矩阵中的每个数都是 0 到 9 之间的数字。现在小蓝想从这个矩阵的第一行第一列画一条折线到第 30 行 60 列,线只能沿水平向右走或竖直向下走,只能在有数字的地方拐弯。小蓝想知道,这样一条线经过的数字的和最大是多少。
174094882455171152761423221685761892795431233411387427793198
650286024865090061389344606618496378829135984076361542097372
601657541200146071777733599818266038012509478351201640618984
143988087783837107349651099683484992553337438088068198972282
890781586124258626539246182119762952003918195325258677229419
698255491250839396799769357665825441616335532825361862146291
503649293440596342887581257444442930778730382520372975343211
325351222640703400531067500454956482168314849207060705673849
265774579830223671554026061117300483012903885770893074783710
083450145620356667677191627276513995926532444279237315785832
411595106453089134746365281031552217482363035280722591085079
053410485925413958279617719034175332412908745680774313630190
429314820559328748143552689295945058801322270313370955837837
939182801848609300876356583948397645861551964542532682663945
625356614462682551015176002433628234343684739800880514363921
982340231989891351425389287014819359798014755509282450440511
590838726938103384801541373585690893606978941566666714061214
952341523168827712604946036245881214982452998386986623826275
782780208928205527678781609589000725521486468983551558405472
149903035076783644195574734088152324666290493119955560594634
905391288186024902215444250421277955403412298227858394469856
607272647132163832860126054679347881638761723785858733108109
249157334220127702410373959720286708183036202841837581704881
367895556630088230650972282944827258473951902831431040790814
079538232104075905120989173307660289899942087873076421916033
622143260549608274076012938515668898707915863945382394851328
164677964192631597026176253407553188801750590935427267220117
591817866992665840378311257621611574856498432538327068011953
631534031790352912617015229051836886166704989498756486878095
690013558017746707412183571476823027885971347137127534455141
线性DP,状态计算为:f[i,j]=max(max(f[i - 1][j], f[i][j - 1])) + v,v是该点的权值。答案为f[30][60]。
答案:592
代码
#include
using namespace std;
const int N = 35, M = 65;
int f[N][M];
char s[N][M];
int main() {
for (int i = 1; i <= 30; i++)
scanf("%s", s[i] + 1);
for (int i = 1; i <= 30; i++)
for (int j = 1; j <= 60; j++)
f[i][j] = max(f[i - 1][j], f[i][j - 1]) + s[i][j] - '0';
cout << f[30][60] << endl;
return 0;
}
小蓝有一个 100 行 100 列的矩阵,矩阵的左上角为 1。其它每个位置正好比其左边的数大 2,比其上边的数大 1 。
例如,第 1 行第 2 列为 3,第 2 行第 2 列 为 4,第 10 行第 20 列为 48。
小蓝想在矩阵中找到一个由连续的若干行、连续的若干列组成的子矩阵,使得其和为 2022,请问这个子矩阵中至少包含多少个元素(即子矩阵的行数和列数的乘积)。
首先我们要构造出这个矩阵, 假设这个矩阵为 a[ ][ ]。
- 矩阵的左上角为 1, 那么 a[1][1] = 1。
- 其它每个位置正好比其左边的数大 2,我们可以构造出第一行 a[1][i] = a[1][i - 1] + 2
- 其它每个位置正好比其上面的数大 1,根据第一行可以构造出其他 9行 a[i][j] = a[i - 1][j - 1] + 1
我们要求一个子矩阵的和,考虑到矩阵长宽只有 100,我们可以通过枚举子矩阵的左上角 (i, j)以及右下角 (k, l),我们用最简单的四重循环来枚举,此时枚举的复杂度为O(n^4), 若此时和为 2022 矩阵的元素个数等于行数和列数的乘积,即(k−i+1)×(l−j+1), 对所有枚举结果取最小值。
查询子矩阵的和是否为 2022我们可以通过预处理二维前缀和O(1)查询。
答案:12
代码
#include
using namespace std;
int a[150][150] , sum[150][150];
int cal(int x1, int y1, int x2, int y2){
return sum[x2][y2] - sum[x2][y1 - 1] - sum[x1 - 1][y2] + sum[x1 - 1][y1 - 1];
}
signed main()
{
a[1][1] = 1;
for(int i = 2;i <= 100;i++) a[1][i] = a[1][i - 1] + 2;
for(int i = 2;i <= 100;i++)
for(int j = 1;j <= 100;j++)
a[i][j] = a[i - 1][j] + 1;
for(int i = 1;i <= 100;i++){
for(int j = 1;j <= 100;j++)
sum[i][j] = sum[i][j - 1] + a[i][j];
for(int j = 1;j <= 100;j++)
sum[i][j] += sum[i - 1][j];
}
int ans = 100 * 100;
for(int i = 1;i <= 100;i++)
for(int j = 1;j <= 100;j++)
for(int k = i;k <= 100;k++)
for(int l = j;l <= 100;l++)
if(cal(i, j, k, l) == 2022)
ans = min(ans,(k - i + 1) * (l - j + 1));
cout << ans << '\n';
return 0;
}
将 2022 拆分成不同的质数的和,请问最多拆分成几个?
求出2~2022的质数,把它看成一个0-1背包问题的话,每一个质数看做一个物品,质数的大小为物品质量,重质量不超出2022,最多能装多少个质数。
答案:33
代码
#include
using namespace std;
const int N = 2030;
int f[N][N];
int primes[N];//2~2022的质数
int n;
int cnt = 1;//质数的个数
bool isprime(int n) {
for (int i = 2; i <= n / i; i++)
if (n % i == 0)
return false;
return true;
}//判断是否为质数(素数)
int main() {
for (int i = 2; i <= 2022; i++)
if (isprime(i))
primes[cnt++] = i;
for (int i = 1; i < cnt; i++)
for (int j = 2; j <= 2022; j++) {
if (primes[i] > j)
f[i][j] = f[i - 1][j];
else
f[i][j] = max(f[i - 1][j], f[i - 1][j - primes[i]] + 1);
}
cout << f[cnt - 1][2022] << endl;
return 0;
}
多练习进制问题、日期问题(围绕2022~2023)、数学问题、矩阵问题、拆分问题,
熟练掌握枚举、动态规划、0-1背包问题等等。
+✏️+⭐️是对博主最大的鼓励与支持!!!