紫书第三章 数组和字符串
例题
开灯问题
有n台灯,k个人,第1个人把所有灯打开,第2个把为2倍数的灯打开/关闭,第3个人把3的倍数的灯打开/关闭,同理,输出最后开着的灯。
输入:7 3
输出:1 5 6 7
简单题不做解析
#include <bits/stdc++.h> using namespace std; //1表示开0,0表示关(运用异或) int main() { vector<bool> light; int n,k; cin >> n >> k; light.resize(n+1,false); for(int i = 1; i <= k; ++i){ for(int j = 1; j <= n; ++j){ if(j%i == 0) light[j] = !light[j]; } } for(int i = 1; i <= n; ++i){ if(light[i]) cout << i << " "; } cout << endl; return 0; }
蛇形填数
输入一个整数n(1<=n<=100),完成蛇形填数
输入:4
输出:
10 11 12 1
9 16 13 2
8 15 14 3
7 6 5 4
#include <bits/stdc++.h> using namespace std; const int maxn = 110; int a[maxn][maxn] = {0}; int main() { int tot = 0; int n,m; cin >> n; int x = 0,y = n; while(tot < n*n) { while(x < n && a[x+1][y] == 0) a[++x][y] = ++tot; while(y > 1 && a[x][y-1] == 0) a[x][--y] = ++tot; while(x > 1 && a[x-1][y] == 0) a[--x][y] = ++tot; while(y < n && a[x][y+1] == 0) a[x][++y] = ++tot; } for(int i = 1; i <= n; ++i){ for(int j = 1; j <= n; ++j) printf("%3d ",a[i][j]); cout << endl; } return 0; }
竖式问题
找出所有形如 abc * de(三位数乘以两位数)的算式,使得在完整的竖式中,所有数字都属于一个特定的数字集合。输入数字集合(相邻数字之间没有空格),输出所有竖式。每个竖式前应有编号,之后应有一个空行。最后输出解的总数。具体格式见样例输出(空格显示成点)。
样例输入:2357
解题思路:将五个数字拼接为一个字符串,对此字符串调用find函数,查看是否符合要求
#include <bits/stdc++.h> using namespace std; int main() { string need; cin >> need; int cnt = 0; for(int i = 100; i <= 999; ++i) for(int j = 10; j <= 99; ++j) { bool ok = true; string buf = to_string(i)+to_string(j)+to_string(i*j)+to_string(i*(j%10))+to_string(i*(j/10)); for(int i = 0; i < buf.size(); ++i){ if(need.find(buf[i]) == string::npos) {ok = false;break;} } if(ok){ ++cnt; cout << "<" << cnt << ">" << endl; printf("%5d\nX%4d\n----\n%5d\n%4d\n-----\n%5d\n",i,j,i*(j%10),i*(j/10),i*j); } } cout << "The number of solutions =" << cnt << endl; return 0; }
Tex中的引号(uva272)
原题链接:https://vjudge.net/problem/UVA-272
题解:左引号换``,右引号换'',简单题
#include <bits/stdc++.h> using namespace std; int main() { char c; bool left = true; while((c = getchar()) != EOF) { if(c == '"'){ cout << (left?"``":"''"); left = !left; } else cout << c; } return 0; }
WERTYU (uva10082)
原题链接:https://vjudge.net/problem/UVA-10082
题解:预处理字符串记录键盘键位,非空格字符查找字符串,输出其前一个字符
#include <bits/stdc++.h> using namespace std; int main() { string s = "1234567890-=QWERTYUIOP[]\ASDFGHJKL;'ZXCVBNM,./"; char c; while((c = getchar()) != EOF){ if(!isspace(c)){ int pos = s.find(c); cout << s[pos-1]; } else cout << c; } return 0; }
回文词(uva401)
原题链接:https://vjudge.net/problem/UVA-401
题解:回文的判断肯定都会,镜像就是映射一下就行
利用map的解法:
#include <iostream> #include <map> using namespace std; string c = "AEHIJLMOSTUVWXYZ12358"; string r = "A3HILJMO2TUVWXY51SEZ8"; map<char,char> rev; const string answer[4] = {"not a palindrome","a regular palindrome","a mirrored string","a mirrored palindrome"}; char revchar(char a) { if(rev.find(a) == rev.end()) return ' '; return rev[a]; } int main() { string s; for(int i = 0; i < c.size(); ++i) rev[c[i]] = r[i]; while(cin >> s) { int p = 1,m = 1; int len = s.size(); for(int i = 0; i <= len/2; ++i) { if(s[i] != s[len-1-i]) { p = 0;} if(revchar(s[i]) != s[len-1-i]) m = 0; } cout << s << " -- is " << answer[p+m*2] << "." << endl;
cout << endl; } return 0; }
仅用字符串完成映射:
#include <iostream> using namespace std; string r = "A 3 HIL JM O 2TUVWXY51SE Z 8 "; const string answer[4] = {"not a palindrome","a regular palindrome","a mirrored string","a mirrored palindrome"}; char revchar(char a) { if(a >= 'A' && a <= 'Z') return r[a-'A']; return r[a-'0'+25]; } int main() { string s; while(cin >> s) { int p = 1,m = 1; int len = s.size(); for(int i = 0; i <= len/2; ++i) { if(s[i] != s[len-1-i]) { p = 0;} if(revchar(s[i]) != s[len-1-i]) m = 0; } cout << s << " -- is " << answer[p+m*2] << "." << endl;
cout << endl;
}
return 0; }
java用map:
import java.util.Scanner; import java.util.HashMap; public class Main{ public static void main(String[] args){ Scanner reader = new Scanner(System.in); String c = "AEHIJLMOSTUVWXYZ12358"; String r = "A3HILJMO2TUVWXY51SEZ8"; HashMap<Character,Character> rev = new HashMap<>(); final String answer[] = {"not a palindrome","a regular palindrome","a mirrored string","a mirrored palindrome"}; for(int i = 0; i < c.length(); ++i){ rev.put(c.charAt(i),r.charAt(i)); } String s; while(reader.hasNext()) { int p = 1, m =1; s = reader.next(); for(int i = 0; i <= s.length()/2; ++i){ if(s.charAt(i) != s.charAt(s.length()-1-i)) p = 0; if(revChar(rev,s.charAt(i)) != s.charAt(s.length()-1-i)) m = 0; } System.out.println(s+" -- is "+answer[p+m*2]+"."); System.out.println(); } } public static char revChar(HashMap<Character,Character> map,char a){ if(!map.containsKey(a)) return ' '; return map.get(a); } }
猜数字游戏的提示(UVA 340)
原题链接:https://vjudge.net/problem/UVA-340
题解:统计出猜测串和密码串位置相同数字相同的位置个数即为A,统计出猜测串中和密码串中各数字出现的次数,其最小值加入到B中,B的结果为B-A(A:位置相同数字相同的个数 B:位置不同数字相同的个数)
#include <iostream> #include <vector> using namespace std; //情况A:数相同且位置相同的总数 //情况B:数相同但位置不同的总数 int main() { int kase = 0; int n; vector<int> code; vector<int> guess; while(cin >> n && n) { kase++; cout << "Game " << kase << ":" << endl; code.resize(n); guess.resize(n); for(int i = 0; i < n; ++i) cin >> code[i]; for(;;){ int A = 0, B = 0; for(int i = 0; i < n; ++i) { cin >> guess[i]; if(guess[i] == code[i]) A++; } if(guess[0] == 0) break; for(int i = 1; i <= 9; ++i){ int c1 = 0, c2 = 0; //统计数字i在密码序列和猜测序列中出现的个数 for(int j = 0; j < n; ++j){ if(guess[j] == i) c1++; if(code[j] == i) c2++; } B += c1<c2?c1:c2; } printf(" (%d,%d)\n",A,B-A); } } return 0; }
生成元(uva1583)
题解:如果每次对于数字m都去遍历m-1一次计算生成元未免太费时,可以预处理先计算出从1~100000的结果,得出生成元表
#include <iostream> #include <cstdio> #define maxn 100005 using namespace std; int ans[maxn]; int main() { int t; scanf("%d",&t); for(int i = 1; i <= maxn-5; ++i){ int result = i; int temp = i; while(temp){ result += temp%10; temp /= 10; } if(!ans[result]) ans[result] = i; //有的数有多个生成元取小的那个 } int n; while(t--) { cin >> n; cout << ans[n] << endl; } return 0; }
得分(UVA1585)
原题链接:https://vjudge.net/problem/UVA-1585
题解:简单题,记录连续O,遇到X变为1即可
#include <iostream> using namespace std; int main() { string s; int T; cin >> T; while(T--) { cin >> s; int n = s.size(); int ans = 0; int m = 1; for(int i = 0; i < n; ++i) { if(s[i] == 'O') { ans += m; m++; } else m = 1; } cout << ans << endl; } return 0; }
分子量(UVA1586)
原题链接:https://vjudge.net/problem/UVA-1586
#include <iostream> #include <cstdio> #include <cctype> using namespace std; double mol[4] = {12.01,1.008,16.00,14.01}; int main() { string str; int T; scanf("%d",&T); while(T--) { cin >> str; double ans = 0.0; int n = str.size(); for(int i = 0; i < n; ++i){ if(isalpha(str[i])){ int t = 0; for(int j = i+1; j < n ; ++j){ if(!isdigit(str[j])) break; t = t*10+(str[j]-'0'); } if(t == 0) t = 1; if(str[i] == 'C') ans += mol[0]*t; else if(str[i] == 'H') ans += mol[1]*t; else if(str[i] == 'O') ans += mol[2]*t; else ans += mol[3]*t; } } printf("%.3f\n",ans); } return 0; }
数数字(UVA1225)
原题链接:https://vjudge.net/problem/UVA-1225
#include <cstdio> #include <iostream> #include <cstring> using namespace std; int main() { int n,T; int c[10]; scanf("%d",&T); while(T--) { cin >> n; memset(c,0,sizeof(c)); for(int i = 1; i <= n; ++i){ int t = i; while(t){ c[t%10]++; t /= 10; } } for(int i = 0; i < 10; ++i) { cout << c[i]; if(i != 9) cout << " "; } cout << endl; } return 0; }
周期串(UVA455)
原题链接:https://vjudge.net/problem/UVA-445
题解:若为该串周期t,则s[i] == s[i+t]并同时利用约瑟夫环即s[i] == s[(i+t)%len],故我们只要从周期1开始往前遍历即可。
#include <iostream> using namespace std; int main() { string s; int t; cin >> t; while(t--) { cin >> s; int n = s.size(); int ans = 1,i; while(1) { for(i = 0; i < n; ++i) if(s[i] != s[(i+ans)%n]) break; if(i == n) break; ans++; } cout << ans << endl; if(t != 0) cout << endl; } return 0; }
谜题(UVA227)
原题链接:https://vjudge.net/problem/UVA-227
题解:简单模拟题
#include <iostream> #include <cstdio> using namespace std; int main() { char board[5][5]; char c; int kase = 0, x, y; while((c = getchar()) && c != 'Z') { ++kase; board[0][0] = c; if(c == ' ') x = 0,y = 0; for(int i = 1; i < 5; ++i) { board[0][i] = getchar(); if(board[0][i] == ' ') x = 0, y = i; } getchar(); for(int i = 1; i < 5; ++i){ for(int j = 0; j < 5; ++j) { board[i][j] = getchar(); if(board[i][j] == ' ') x = i, y = j; } getchar(); } /*cout << "test" << endl; for(int i = 0; i < 5; ++i){ for(int j = 0; j < 5; ++j) putchar(board[i][j]); cout << endl; }*/ string order; bool flag = true; while(cin >> order){ getchar(); //take enter int len = order.size(); int i; for(i = 0; i < len && flag; ++i){ if(order[i] == 'A'){ if(x-1 < 0) { flag = !flag;break;} swap(board[x][y],board[x-1][y]); x -= 1; } else if(order[i] == 'B'){ if(x+1 >= 5) { flag = !flag;break;} swap(board[x][y],board[x+1][y]); x += 1; } else if(order[i] == 'L'){ if(y-1 < 0) { flag = !flag;break;}; swap(board[x][y],board[x][y-1]); y--; } else if(order[i] == 'R'){ if(y+1 >= 5) { flag = !flag;break;} swap(board[x][y],board[x][y+1]); y++; } } if(order[len-1] == '0') break; } if(kase != 1) cout << endl; printf("Puzzle #%d:\n",kase); if(flag){ for(int i = 0; i < 5; ++i){ for(int j = 0; j < 5; ++j) { cout << board[i][j] ; if(j != 4) cout << " ";} cout << endl; } } else cout << "This puzzle has no final configuration." << endl; } }
纵横字谜答案(UVA232)
#include <iostream> #include <cstdio> #include <cstring> using namespace std; int main() { int r,c; char board[12][12]; int num[12][12]; int kase = 0; while(cin >> r && r != 0) { ++kase; cin >> c; getchar(); memset(num,0,sizeof(num)); for(int i = 0; i < r; ++i){ for(int j = 0; j < c; ++j) board[i][j] = getchar(); getchar(); } //test /*for(int i = 0; i < r; ++i){ for(int j = 0; j < c; ++j) cout << board[i][j] << " "; cout << endl; }*/ int c1 = 0; for(int i = 0; i < r; ++i) { for(int j = 0; j < c; ++j) { if((i == 0 || j == 0 || board[i-1][j] == '*' || board[i][j-1] == '*') && board[i][j] != '*') num[i][j] = ++c1; } } //test /*for(int i = 0; i < r; ++i){ for(int j = 0; j < c; ++j) cout << num[i][j] << " "; cout << endl; }*/ if(kase != 1) cout << endl; printf("puzzle #%d:\n",kase); cout << "Across" << endl; for(int i = 0; i < r; ++i) for(int j = 0; j < c; ++j) { if(num[i][j] != 0){ printf("%3d.",num[i][j]); for(; j < c; ++j) { cout << board[i][j]; if(j != c-1 && board[i][j+1] == '*') break; } cout << endl; } } cout << "Down" << endl; for(int i = 0; i < r; ++i) for(int j = 0; j < c; ++j) { if(num[i][j] != 0 && (i == 0 || board[i-1][j] == '*')){ printf("%3d.",num[i][j]); for(int k = i; k < r; ++k){ if(board[k][j] == '*') break; cout << board[k][j]; } cout << endl; } } } return 0; }
DNA序列(UVA202)
#include <iostream> #include <cstdio> #include <map> #include <cstring> using namespace std; int des[4] = {'A','C','G','T'}; map<char,int> dict = { {'A',0},{'C',1},{'G',2},{'T',3} }; int main() { int T,m,n; string a[55]; scanf("%d",&T); while(T--) { int cnt[4]; int haming = 0; string ans; cin >> n >> m; for(int i = 0; i < n; ++i) cin >> a[i]; for(int i = 0; i < m; ++i) { memset(cnt,0,sizeof(cnt)); for(int j = 0; j < n; ++j){ cnt[dict[a[j][i]]]++; } int mx = 0, k = 0; for(int j = 0; j < 4; ++j) { if(mx < cnt[j]) mx = cnt[j], k = j; } haming += n-mx; ans += des[k]; } cout << ans << endl; cout << haming << endl; } return 0; }
循坏小数(UVA202)
题解:因为除数不会变,故出现相同的余数即是循坏小数,我们可以用两个数组
int cnt[maxn]; //记录小数第一次出现的位置
int ans[maxn]; //记录每个位置上的值
可循环判断余数:
while(cnt[c] == 0)
{
tot++;
cnt[c] = tot; //记录第一次出现的位置
ans[tot] = c*10/b; //记录位置上的数
c = c*10%b;
}
#include <iostream> #include <cstdio> #include <cstring> //模拟笔算除法 //判断循坏:再次出现相同的余数 const int maxn = 3010; using namespace std; int cnt[maxn]; //记录小数第一次出现的位置 int ans[maxn]; //记录每个位置上的值 int main() { int a,b; int tot; while(~scanf("%d%d",&a,&b)) { memset(cnt,0,sizeof(cnt)); memset(ans,0,sizeof(ans)); tot = 0; printf("%d/%d = %d.",a,b,a/b); int c = a%b; while(cnt[c] == 0) { tot++; cnt[c] = tot; //记录第一次出现的位置 ans[tot] = c*10/b; //记录位置上的数 c = c*10%b; } for(int i = 1; i < cnt[c]; ++i) { printf("%d",ans[i]); } printf("("); if(tot-cnt[c]+1 > 50) { for(int i = cnt[c],j = 0; j < 50; ++j) printf("%d",ans[i+j]); printf("...)\n"); } else { for(int i = cnt[c]; i <= tot; ++i) printf("%d",ans[i]); printf(")\n"); } printf(" %d = number of digits in repeating cycle\n\n",tot-cnt[c]+1); } return 0; }
子序列(UVA10340)
#include <iostream> using namespace std; int main() { string s,t; while(cin >> s >> t) { int sl = s.size(); int tl = t.size(); int index = 0; for(int i = 0; i < tl; ++i) if(t[i] == s[index]) index++; cout << (index == sl?"Yes":"No") << endl; } return 0; }
盒子(UVA1587)
题解:
//组成盒子:前提三对相同的面(短边相同长边相同)
//拥有3对后:进行排序,其实就是 左 上 前 三个面,左的长边等于前的短边 左的短边等于上的短边 前的长边等于上的长边
//左肯定是最小的,上和前也是确定的,因为上有一条短边
c++11 to_string解法:
#include <iostream> #include <cstdio> #include <string> #include <utility> #include <algorithm> using namespace std; //组成盒子:前提三对相同的面(短边相同长边相同) //拥有3对后:进行排序,其实就是 左 上 前 三个面,左的长边等于前的短边 左的短边等于上的短边 前的长边等于上的长边 //左肯定是最小的,上和前也是确定的,因为上有一条短边 bool check(pair<int,int> p[]) { return p[0].first == p[1].first && p[0].second == p[2].first && p[1].second == p[2].second; } int main() { int w[6],h[6]; while(~scanf("%d%d",&w[0],&h[0])) { for(int i = 1; i < 6; ++i) scanf("%d%d",&w[i],&h[i]); string buf[6]; for(int i = 0; i < 6; ++i) { if(w[i] < h[i]) buf[i] = to_string(w[i]) +" "+to_string(h[i]); else buf[i] = to_string(h[i]) +" "+to_string(w[i]); //cout << buf[i] << endl; } int cnt = 0; //记录是否有3对 pair<int,int> p[3]; int vis[6] = {0}; //找到三对 for(int i = 0; i < 6; ++i) { if(!vis[i]) for(int j = 0; j < 6; ++j) { if(j == i || vis[j]) //已用作一对 continue; if(buf[i] == buf[j]) { p[cnt].first = stoi(buf[i].substr(0,buf[i].find_first_of(" "))); p[cnt].second = stoi(buf[i].substr(buf[i].find_first_of(" "))); vis[i] = vis[j] = 1; //已成为1对标记 cnt++; break; } } } sort(p,p+3); if(cnt == 3 && check(p)) cout << "POSSIBLE" << endl; else cout << "IMPOSSIBLE" << endl; } return 0; }
c++11前:
#include <bits/stdc++.h> using namespace std; pair<int,int> p[3]; //组成盒子:前提三对相同的面(短边相同长边相同) //拥有3对后:进行排序,其实就是 左 上 前 三个面,左的长边等于前的短边 左的短边等于上的短边 前的长边等于上的长边 //左肯定是最小的,上和前也是确定的,因为上有一条短边 //长方形每对面中两条边都会其他两对面中的一条边相等 int check() //1:第一对的最短边必然等于第二对的最短边 2:第二对的最长边必然等于第三对最长边(前提条件优先按短边排序相同情况按长边排序) { return p[0].first == p[1].first && p[0].second == p[2].first && p[1].second == p[2].second; } //1:按first长短排序,第一对的first和第二对的first必然是重合的边 //2:在1.2对first相同的情况下,第二对second比第一对的second长,故第二对second与第三对second是重合的边 int main() { int w[6],h[6]; while(~scanf("%d%d",&w[0],&h[0])) { for(int i = 1; i < 6; i++) scanf("%d%d",&w[i],&h[i]); char buf[6][30]; for(int i = 0; i < 6; i++) { if(w[i] < h[i]) sprintf(buf[i],"%d %d",w[i],h[i]); else sprintf(buf[i],"%d %d",h[i],w[i]); } int cnt = 0; int vis[6] = {0}; //找到一对后将其标记 for(int i = 0; i < 6; i++) { if(!vis[i]) for(int j = 0; j < 6; j++) { if(i == j || vis[j]) continue; if(strcmp(buf[i],buf[j]) == 0) { if(h[i] > w[i]) { p[cnt].first = w[i]; p[cnt].second = h[i]; } else { p[cnt].first = h[i]; p[cnt].second = w[i]; } vis[i] = vis[j] = 1; cnt++; break; } } } if(cnt == 3) { sort(p,p+3); /*test for(int i = 0; i < 3; i++) printf("%d %d\n",p[i].first,p[i].second); */ } if(cnt == 3 && check()) printf("POSSIBLE\n"); else printf("IMPOSSIBLE\n"); } return 0; }
换低档配置(UVA1587)
题解:一个为底另一位顶,为底不动,顶部从底部头至尾遍历找到全程无超过3的情况。
注意:翻转会有不同结果
#include <iostream> #include <cstdio> using namespace std; //注意:翻转的结果不同 int main() { string top,low; while(cin >> top >> low) { int n = top.size(), m = low.size(); int ans = n+m; for(int i = 0; i < m; ++i) //low为底 { int l = 0; //用于记录超出底部的长度 bool flag = true; //记录有无超过3限定 for(int j = 0; j < n; ++j) { if(i+j == m) { l += n-j; break; } else { if(low[i+j]+top[j]-2*'0' == 4) { flag = false; break; } } } if(flag) { ans = min(ans,m+l); break; } } for(int i = 0; i < n; ++i) //以top为底 { int l = 0; bool flag = true; for(int j = 0; j < m; ++j) { if(i+j >= n) { l += m-j; break; } else if(top[i+j]+low[j]-2*'0' == 4) { flag = false; break; } } if(flag) { ans = min(ans,n+l); break; } } cout << ans << endl; } return 0; }
浮点数(UVA11809)
题解:
#include <iostream> #include <cstdio> #include <cmath> #include <sstream> #define ESP 1e-4 using namespace std; int main() { //M:0~9 E:1~30 int ansi[10][31]; double ansd[10][31]; for(int i = 0; i <= 9; ++i) //M:0-9 { for(int j = 1; j <= 30; ++j) //E:1-30 { double t = log10(1-pow(2,-i-1))+(pow(2,j)-1)*log10(2); ansi[i][j] = (int)t; ansd[i][j] = pow(10,t-ansi[i][j]); //把log10(A)转换为A } } string s; while(cin >> s) { for(auto p = s.begin(); p != s.end(); ++p) if(*p == 'e') *p = ' '; stringstream is(s); double A; int B; is >> A >> B; if(fabs(A-0) <= ESP && B == 0) break; bool flag = true; for(int i = 0; i <= 9 && flag; ++i) for(int j = 1; j <= 30 && flag; ++j) { if(B == ansi[i][j] && fabs(A-ansd[i][j]) <= ESP) { cout << i << " " << j << endl; flag = false; } } } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!