1、以下是一个 25 行 25 列的字母矩阵,全部由字母 A 和 B 组成。
AAAAAAABABBAABABABAAAAAAA
ABBBBBABBAABBBBBABABBBBBA
ABAAABABBBABAABBBBABAAABA
ABAAABABBBBBAABAABABAAABA
ABAAABABBABABBABABABAAABA
ABBBBBABBBABAABBBBABBBBBA
AAAAAAABABABABABABAAAAAAA
BBBBBBBBABAABABBBBBBBBBBB
AABAABABBAAABBAAABABBBBBA
ABBABABBBABBAAAABBBBAAAAB
BBBBAAABABAABABAABBBAABBA
BBAABABABAAAABBBAABBAAAAA
ABABBBABAABAABABABABBBBBA
AAAABBBBBABBBBAAABBBABBAB
AABAABAAABAAABAABABABAAAA
ABBBBBBBBABABBBBABAABBABA
ABBBAAABAAABBBAAAAAAABAAB
BBBBBBBBABBAAABAABBBABBAB
AAAAAAABBAAABBBBABABAABBA
ABBBBBABBAABABAAABBBABBAA
ABAAABABABBBAAAAAAAAAABAA
ABAAABABABABBBABBAABBABAA
ABAAABABBABBABABAABAABAAA
ABBBBBABABBBBBABBAAAABAAA
AAAAAAABAABBBAABABABBABBA
请问在这个矩阵中有多少个字母A?318个
int main(){
string in="AAAAAAABABBAABABABAAAAAAAABBBBBABBAABBBBBABABBBBBAABAAABABBBABAABBBBABAAABAABAAABABBBBBAABAABABAAABAABAAABABBABABBABABABAAABAABBBBBABBBABAABBBBABBBBBAAAAAAAABABABABABABAAAAAAABBBBBBBBABAABABBBBBBBBBBBAABAABABBAAABBAAABABBBBBAABBABABBBABBAAAABBBBAAAABBBBBAAABABAABABAABBBAABBABBAABABABAAAABBBAABBAAAAAABABBBABAABAABABABABBBBBAAAAABBBBBABBBBAAABBBABBABAABAABAAABAAABAABABABAAAAABBBBBBBBABABBBBABAABBABAABBBAAABAAABBBAAAAAAABAABBBBBBBBBABBAAABAABBBABBABAAAAAAABBAAABBBBABABAABBAABBBBBABBAABABAAABBBABBAAABAAABABABBBAAAAAAAAAABAAABAAABABABABBBABBAABBABAAABAAABABBABBABABAABAABAAAABBBBBABABBBBBABBAAAABAAAAAAAAAABAABBBAABABABBABBA";
int cnt=0,c=0;
for (int i=0;i<in.size();i++){
if (in[i]=='A') cnt+=1;
else c=1;
}
cout<<cnt;
return 0;
}
2、如果一个整数的某个数位包含 2 则称这个数为一个“最2数字”。例如:102、2021 都是最2数字。请问在 1(含) 到 2021(含) 中,有多少个最2数字。
564个
bool is2(int x){
while (x){
if (x%10==2) return true;
x/=10;
}
return false;
}
int main(){
int cnt=0;
for (int i=1;i<2022;i++){
if (is2(i)) cnt+=1;
}
cout<<cnt;
return 0;
}
3、 有一个整数 A=2021,每一次,可以将这个数加 1 、减 1 或除以 2,其中除以 2 必须在数是偶数的时候才允许。例如,2021 经过一次操作可以变成 2020、2022。再如,2022 经过一次操作可以变成 2021、2023 或 1011。请问,2021 最少经过多少次操作可以变成 1。
改:14次
修正思路: 递归求解:奇数+1可除以4时只需要加1除以2除以2三步,否则-1除以2后还得-1除以2要四步。所以奇数要分情况讨论+1或-1,偶数%2才会使数越来越小。
int mini=1000;
void dfs(int x,int cnt){
if (x==1){
mini=min(cnt,mini);
return;
}
else{
if (x%2){ //奇数
if ((x+1)%4==0) dfs(x+1,cnt+1);
else dfs(x-1,cnt+1);
}
else{//偶数
dfs(x/2,cnt+1);
}
}
}
int main(){
dfs(2021,0);
cout<<mini;
return 0;
}
4、对于一个 n 行 m 列的表格,我们可以使用螺旋的方式给表格依次填上正整数,我们称填好的表格为一个螺旋矩阵。
例如,一个 4 行 5 列的螺旋矩阵如下:
1 2 3 4 5
14 15 16 17 6
13 20 19 18 7
12 11 10 9 8
请问,一个 30 行 30 列的螺旋矩阵,第 20 行第 20 列的值是多少? 819
思路: 按它给的顺序用双重for循环把数组填充完整,输出(20,20)即可。
int main(){//矩阵初始化
int cost[31][31];
for (int i=1;i<31;i++){
for (int j=1;j<31;j++) cost[i][j]=0;
}
//螺旋填充
int num=1;
/*比较耗时,因为要想边界
for (int x=1;x<16;x++){//重复多少次
for (int i=x;i<=31-x;i++){
if (cost[x][i]==0) cost[x][i]=num++;
}
for (int j=x;j<=31-x;j++){
if (cost[j][31-x]==0) cost[j][31-x]=num++;
}
for (int i=31-x;i>=x;i--){
if (cost[31-x][i]==0) cost[31-x][i]=num++;
}
for (int j=31-x;j>=x;j--){
if (cost[j][x]==0) cost[j][x]=num++;
}
}*/
//快速方法:扫描找没有经过的地方即可
for (int x=1;x<16;x++){//重复多少次
for (int i=1;i<31;i++){//上
if (cost[x][i]==0) cost[x][i]=num++;
}
for (int j=1;j<31;j++){//右
if (cost[j][31-x]==0) cost[j][31-x]=num++;
}
for (int i=30;i>0;i--){//下
if (cost[31-x][i]==0) cost[31-x][i]=num++;
}
for (int j=30;j>0;j--){//左
if (cost[j][x]==0) cost[j][x]=num++;
}
}
cout<<cost[20][20];
return 0;
}
5、一棵二叉树有2021个结点。该树满足任意结点的左子树结点个数和右子树的结点个数之差最多为1。定义根结点的深度为0,子结点的深度比父结点深度多1。
请问,树中深度最大的结点的深度最大可能是多少? 10
思路: 深度为n的二叉树最多有2**(n+1)-1个节点.。当节点为2021时,最多深度为10。
int main(){
int x=0,t=1,sum=1;
while (sum<2021){
x+=1;//深度
t*=2;//叶子节点
sum+=t;//总的节点个数
cout<<x<<" "<<t<<" "<<sum<<endl;
}
return 0;
}
6、一个和尚要挑水,每次最多能挑 a 千克,水缸最多能装 t 千克,开始时水缸为空。请问这个和尚最少要挑多少次可以将水缸装满?
【输入格式】输入一行包含两个整数 a, t,用一个空格分隔。
【输出格式】输出一行包含一个整数,表示答案。
【样例输入】20 2021
【样例输出】102
评测用例规模与约定:对于所有评测用例,1 <= a <= 100,1 <= t <= 10000。
思路: 贪心算法,是当我傻吗?
int main(){
int a,t;
cin>>a>>t;
if (t%a==0) cout<<t/a;
else cout<<t/a+1;
return 0;
}
7、在金融领域,通常将金额的百位和千位之间、十万位和百万位之间增加逗号(千分位分隔符),以方便阅读。一般从个位开始,每三位之前增加一个逗号。例如:1234567890.00 通常写成 1,234,567,890.00。注意小数点后固定保留 2 位。给定一个包含千分位分隔符的数值,请读入后输出对应的不含千分位的数值,小数点仍然保留 2 位。
【输入格式】输入一行包含一个由千分位分隔符的数值,恰好有 2 位小数。
【输出格式】输出不含千分位分隔符的数值,保留 2 位小数。
【样例输入】1,234,567,890.00
【样例输出】1234567890.00
评测用例规模与约定:对于所有评测用例,给定的数值整数部分不超过12位。
思路: 字符串去掉逗号即可,是当我傻吧?
int main(){
string in;
cin>>in;
for (int i=0;i<in.size();i++){
if (in[i]!=',') cout<<in[i];
}
return 0;
}
8、小蓝有一个插板形状用一个 n * m 的01矩阵表示,0 表示板面,1 表示插孔。还有一个插头用一个 r * c 的01矩阵表示,0 表示没有伸出的部分,1 表示伸出的部分。插头伸出的部分必须插在插孔里面。为了安全,插头插到面板上不能有任何部分超过插板边界(包括没有伸出的部分)。插头和插板都不能旋转,也不能翻转。请求出插头插入插板的合理位置。
【输入格式】
输入的第一行包含两个整数 n, m。
接下来 n 行,每行一个长度为 m 的01串,表示插板的形状。
接下来一行包含两个整数 r, c。
接下来 r 行,每行一个长度为 c 的01串,表示插头的形状。
【输出格式】
如果插头没办法安全插入插板中,输出“NO”。否则输出两个数 a, b,表示插头的第 1 行第 1 列对应插板的第 a 行第 b 列。如果有多种情况满足要求,输出 a 最小的方案,如果 a 最小的方案有多个,输出在 a 最小的前提下 b 最小的方案。
【样例输入】
3 4
0110
0000
0000
3 3
000
010
000
【样例输出】NO
【样例说明】在插头不超出范围的前提下无法插入。
【样例输入】
4 7
1110100
1101111
0001111
0000011
2 3
111
011
【样例输出】2 4
评测用例规模与约定:对于 50% 的评测用例,2 <= n, m, r, c <= 20。
对于所有评测用例,2 <= n, m, r, c <= 100。**
思路: 用int矩阵存储插头和插板,对于每个合法的左上角,遍历查看插头=1的地方是不是插板=1,只要最小值则找到就跳出循环。
int main(){//输入插板和插头
int n,m,r,c;
cin>>n>>m;
char ch;
int ban[n+1][m+1];
for (int i=1;i<=n;i++){
for (int j=1;j<=m;j++){
cin>>ch;
ban[i][j]=ch-'0';
}
}
cin>>r>>c;
int tou[r+1][c+1];
for (int i=1;i<=r;i++){
for (int j=1;j<=c;j++){
cin>>ch;
tou[i][j]=ch-'0';
}
}
//输出处理
int f,x,y;
for (int i=1;i<=n-r+1;i++){
for (int j=1;j<=m-c+1;j++){
x=i,y=j,f=1;//每个可以的左上角看能否匹配
for (int p=1;p<=r;p++){
for (int q=1;q<=c;q++){
if (tou[p][q]==1 && ban[x+p-1][y+q-1]==0) f=0;
}
}
if (f==1) break;//已找到
}
if (f==1) break; //找序号最小
}
if (f==0) cout<<"NO";
else cout<<x<<" "<<y;
return 0;
}
9、给定正整数 a, b, c,请问有多少个正整数,是其中至少两个数的约数。
【输入格式】输入一行包含三个正整数 a, b, c。
【输出格式】输出一行包含一个整数,表示答案。
【样例输入】30 70 35
【样例输出】6
【样例说明】1、2、5、7、10、35满足条件。
【评测用例规模与约定】
对于 50% 的评测用例,1 <= a, b, c <= 1000000。
对于所有评测用例,a, b, c 不超过 10 ** 12(10的12次方)。
修正思路: 用函数找最小数和最大数,用和减去即可得到中间数,划分区域寻找公约数。
typedef long long ll;
int main(){
ll a,b,c,cnt=0;
cin>>a>>b>>c;
ll mini=min(a,min(b,c)),maxi=max(a,max(b,c)),mid=a+b+c-maxi-mini;
for (ll i=1;i<=mini;i++){ //小于最小数
if (mini%i==0){
if (mid%i==0) cnt+=1;
else if (maxi%i==0) cnt+=1;
}
else if (mid%i==0 && maxi%i==0) cnt+=1;
}
for (ll i=mini+1;i<=mid;i++){//最小数和中间数中间
if (mid%i==0 && maxi%i==0) cnt+=1;
}
cout<<cnt;
return 0;
}
10、汉诺塔是个经典问题,当盘子数量为 n 时,最少需要移动 2 ** n-1 步,其中 2 ** n 表示 2 的 n 次方。小蓝已经玩了一会儿(不一定按最优方案玩),他想知道,对于他目前的局面,最少还需要多少步可以到达目标。
【输入格式】输入的第一行包含三个非负整数 a, b, c,分别表示目前每根柱子上的盘子数。在本题中,n=a+b+c。
第二行包含 a 个整数,相邻的整数之间使用一个空格分隔,表示第一根柱子上的盘子,盘子按从上到下(从小到大)的顺序给出。
第三行包含 b 个整数,相邻的整数之间使用一个空格分隔,表示第二根柱子上的盘子,盘子按从上到下(从小到大)的顺序给出。
第四行包含 c 个整数,相邻的整数之间使用一个空格分隔,表示第三根柱子上的盘子,盘子按从上到下(从小到大)的顺序给出。
【输出格式】输出一行包含一个整数,表示答案。
【样例输入】
1 2 3
1
2 3
4 5 6
【样例输出】7
评测用例规模与约定:对于 30% 的评测用例,2 <= n <= 5。对于所有评测用例,2 <= n <= 60。
思路: 不太会这道题的bfs,copy了大佬的码
#include <bits/stdc++.h>
using namespace std;
#define LL long long
map<string, string> path; // 下一个状态: 当前状态
const int N = 100;
int A[N], B[N], C[N];
int ha = 0, hb = 0, hc = 0; //栈顶
int a, b, c;
string end_state;
char rep = 'A';
map<string, int> res; //已经存在的结果集
// 获得当前ABC 柱子上的状态
string get_state() {
string s = "@";
for (int i = 0; i <= ha; i++) s += (char)(A[i] - 1 + rep);
s.append("#");
for (int i = 0; i <= hb; i++) s += (char)(B[i] - 1 + rep);
s.append("$");
for (int i = 0; i <= hc; i++) s += (char)(C[i] - 1 + rep);
return s;
}
// 根据状态还原数组
void back_state(string s) {
memset(A, 0, sizeof A);
memset(B, 0, sizeof B);
memset(C, 0, sizeof C);
ha = -1, hb = -1, hc = -1;
int state = 0; // 1->A -> @ 2->B -># 3-> C -> $
for (int i = 0; s[i]; i++) {
// 状态改变
if (s[i] == '@') {
state = 1;
continue;
}
if (s[i] == '#') {
state = 2;
continue;
}
if (s[i] == '$') {
state = 3;
continue;
}
if (state == 1) A[++ha] = s[i] - rep + 1;
else if (state == 2) B[++hb] = s[i] - rep + 1;
else if (state == 3) C[++hc] = s[i] - rep + 1;
}
}
queue<string> q;
void move(int (&src)[N], int (&tar)[N], int& src_t, int& tar_t, string s) {
if (src_t != -1 && tar_t == -1 || src[src_t] < tar[tar_t]) {
tar[++tar_t] = src[src_t--];
string next = get_state();
if (res[next] == 0) {
q.push(next);
path[next] = s;
res[next]++;
}
src[++src_t] = tar[tar_t--];
}
}
void bfs(string state) {
res[state]++;
q.push(state);
while (!q.empty()) {
string s = q.front();
q.pop();
if (s == end_state) return;
back_state(s);
move(C, A, hc, ha, s);// C -> A
move(C, B, hc, hb, s);// C -> B
move(A, B, ha, hb, s);// A -> B
move(A, C, ha, hc, s);// A -> C
move(B, A, hb, ha, s);// B -> A
move(B, C, hb, hc, s);// B -> C
}
}
int main() {
cin >> a >> b >> c;
for (int i = 0; i < a; i++) cin >> A[a - i - 1];
for (int i = 0; i < b; i++) cin >> B[b - i - 1];
for (int i = 0; i < c; i++) cin >> C[c - i - 1];
ha = a - 1;
hb = b - 1;
hc = c - 1;
end_state = get_state(); // 获得了 结束条件
//cout << end_state << endl;
back_state(end_state);
// 制作终点状态
memset(A, 0, sizeof A);
memset(B, 0, sizeof B);
memset(C, 0, sizeof C);
int n = a + b + c;
for (int i = 0; i < n; i++) C[i] = n - i;
ha = -1;
hb = -1;
hc = n - 1;
string start = get_state();
//cout << start << endl;
bfs(start);
int cnt = 0;
while (end_state != start) {
end_state = path[end_state];
cnt++;
}
cout<<cnt;
return 0;
}