目录
问题 A: 符文宗师的魔方阵
题目描述
符文宗师是艾里奥斯大陆的一名魔法骑士,通过将不同符文力量结合到剑术中来增强自己的力量。
为了寻求更多强大的符文力量,他开始游历大陆。
一天,他在山涧中发现了一个刻有神秘数字阵列的发光石。多年的冒险经验告诉他,这个发光石不简单,其内隐藏着强大的符文力量。
为了解开发光石的秘密,他去拜访了他的一个炼金术士好友——艾伦。
艾伦告诉他,这个发光石上面的神秘数字阵列是数学中的魔方阵,所谓魔方阵,指的是一个矩阵,它的各行各列的和相同。但是这个魔方阵有一部分数字缺失了,如果能补全这一残缺的魔方阵,那么其内的符文力量自会显现。
艾伦将发光石上面残缺的魔方阵以简单的形式抄了下来,如样例输入所示,方便进行填充。此外,艾伦还通过占星术发现,这个残缺的魔方阵,不会出现一个子矩阵上面的数字完全残缺的情形。
符文宗师向你寻求帮助,希望你能够帮他填充这个残缺的魔方阵。如果你能帮他补全残缺的魔方阵,那么你将能够习得新技能——月光之刃。
输入
输入是一个5行、5列的残缺的魔方矩阵,矩阵的每个元素的取值大于等于1,小于等于100。
魔方阵中缺失数字的个数大于等于1,小于等于4。
为了方便,缺失数字的位置填上了-1。
并且这个残缺的魔方阵中不会出现如下的子矩阵:
-1 -1
-1 -1
具体的输入,可以参考下面的输入样例。
输出
填补完整后的魔方阵。
样例输入 复制
17 24 1 8 15
23 5 7 -1 16
4 6 13 20 22
10 -1 19 21 3
11 18 25 2 9
样例输出 复制
17 24 1 8 15
23 5 7 14 16
4 6 13 20 22
10 12 19 21 3
11 18 25 2 9
提示
每个数字输出时的格式控制符为"%3d".
AC代码:
//abgikl
#include <bits/stdc++.h>
using namespace std;
int main() {
int a[10][10], number[10];
for (int i = 0; i < 5; i++) {
int sum = 0;
for (int j = 0; j < 5; j++) {
cin >> a[i][j];
if (a[i][j] == -1)
sum++;
}
number[i] = sum;
}
for (int i = 0; i < 5; i++) {
int sum = 0;
for (int j = 0; j < 5; j++) {
if (a[j][i] == -1)
sum++;
}
number[i + 5] = sum;
}
int sum[10];
memset(sum, 0, sizeof(sum));
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
if (a[i][j] != -1)
sum[i] += a[i][j];
if (a[j][i] != -1)
sum[i + 5] += a[j][i];
}
}
int ans = 0;
for (int i = 0; i < 5; i++) {
if (number[i] == 0) {
ans = sum[i];
break;
}
}
if (ans == 0) {
for (int i = 0; i < 5; i++) {
if (number[i + 5] == 0) {
ans = sum[i + 5];
break;
}
}
}
for (int i = 0; i < 5; i++) {
if (number[i] == 1) {
for (int j = 0; j < 5; j++) {
if (a[i][j] == -1) {
a[i][j] = ans - sum[i];
break;
}
}
}
}
for (int i = 0; i < 5; i++) {
if (number[i + 5] == 1) {
for (int j = 0; j < 5; j++) {
if (a[j][i] == -1) {
a[j][i] = ans - sum[i + 5];
break;
}
}
}
}
for (int i = 0; i < 5; i++) {
int s = 0;
for (int j = 0; j < 5; j++) {
if (a[j][i] != -1)
s += a[j][i];
}
sum[5 + i] = s;
}
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
if (a[j][i] == -1) {
a[j][i] = ans - sum[i + 5];
}
}
}
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
printf("%3d ", a[i][j]);
}
printf("\n");
}
return 0;
}
问题 B: APP的成绩单
题目描述
APP同学不小心弄乱了班级成绩Excel表格,还是不能撤销的那种。
比如原表格的内容为(按次序分别为:姓名、学号、性别、成绩;用空格分隔):
appmlk 2020401190 girl 80.8
notappmlk 2020401191 boy 98.0
isappmlk 2020401192 boy 100.0
但是弄乱后变为:
2020401190 appmlk 80.8 girl
boy 2020401191 98.0 notappmlk
isappmlk 100.0 2020401192 boy
不过好在只是把每一行内部的顺序弄乱了,行与行之间的数据没有弄混,请你写一个程序帮他把表格内容恢复原状。
输入
第一行包含一个正整数n(1<= n <= 100),代表学生人数。
接下来的n行,每行为每个学生的信息,中间用单个空格隔开;其中必定包含单个学生的姓名、学号、性别和成绩。
姓名只可能包含英文字符、且长度必定超过一个英文字符,且少于50个字符(且不可能与性别的单词重复)。
学号只可能包含数字、且长度必定为10个数字。
性别只可能为“boy”或者“girl”。
成绩只可能为数值,且必定包含一个小数点,小数点后仅保留一位。
输出
把每一行的学生信息按照姓名、学号、性别、成绩排列
学生的排名顺序不变
样例输入 复制
3
2020401190 appmlk 80.8 girl
boy 2020401191 98.0 notappmlk
isappmlk 100.0 2020401192 boy
样例输出 复制
appmlk 2020401190 girl 80.8
notappmlk 2020401191 boy 98.0
isappmlk 2020401192 boy 100.0
AC代码:
//bgikl
#include <bits/stdc++.h>
using namespace std;
int main() {
int n;
string s, name, num, score, gender;
cin >> n;
while (n--) {
for (int i = 0; i < 4; i++) {
cin >> s;
if (s == "girl" || s == "boy")
gender = s;
else if ( s[0] >= 'a' && s[0] <= 'z')
name = s;
else if (s.size() == 10 && s[0] >= '0' && s[0] <= '9')
num = s;
else
score = s;
}
cout << name << " " << num << " " << gender << " " << score << endl;
}
return 0;
}
问题 C: 6.1.4.1 最大的节点
题目描述
给 N 出个点,M 条边的有向图,对于每个点 v,求 A(v) 表示从点出发,能到达的编号最大的点。
输入
第1 行,2 个整数 N, M。
接下来 M 行,每行 2 个整数Ui,Vi,表示边(Ui,Vi)。点用 1, 2, ⋯, N 编号。
输出
N个整数 A(1), A(2), ⋯, A(N)。
样例输入 复制
4 3
1 2
2 4
4 3
样例输出 复制
4 4 3 4
提示
1 ≤ N, M ≤ 100000。
#include <iostream>
#include <vector>
using namespace std;
const int MAXN = 1000; // 根据问题描述调整最大节点数
int reachable[MAXN][MAXN]; // 可达矩阵
int main() {
int N, M, u, v;
cin >> N >> M;
// 初始化可达矩阵
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
reachable[i][j] = (i == j) ? 1 : 0; // 初始化对角线为1,其余为0
}
}
// 读入边并更新可达矩阵
for (int i = 0; i < M; i++) {
cin >> u >> v;
reachable[u - 1][v - 1] = 1; // 节点编号从0开始
}
// 使用Floyd Warshall算法计算传递闭包
for (int k = 0; k < N; k++) {
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (reachable[i][k] && reachable[k][j]) {
reachable[i][j] = 1;
}
}
}
}
// 输出每个节点可达的节点数
for (int i = 0; i < N; i++) {
for (int j = N - 1; j >= 0; j--) {
if (reachable[i][j] == 1) {
cout << j + 1 << " ";
break;
}
}
}
return 0;
}
问题 D: 6.2.2.1 油田
题目描述
石油勘探公司正在按计划勘探地下油田资源。油田是一片长方形地域,工人们将该地域划分为许多小正方形区域,然后使用探测设备分别探测在每一小块正方形区域内是否有油。
含有油的区域被称为油田,如果两个油田相邻(8联通:包括水平、垂直、对角线相邻),则它们是相同油藏的一部分。油藏可能非常大并可能包含许多油田(油田的个数不超过100)。你的工作是确定在这个长方形地域中包含多少不同的油藏。
输入
输入一个或多个长方形地域。
每个地域的第1行为两个正整数m和n(1≤m,n≤100),分别表示地域的行数和列数;
如果m=0或n=0 表示输入结束,否则此后有m行,每行都有n个字符。
每个字符都对应一个正方形区域,字符*表示没有油,字符@表示有油。
输出
单行输出每个地域的油藏个数。
样例输入 复制
1 1
*
3 5
*@*@*
**@**
*@*@*
1 8
@@****@*
5 5
****@
*@@*@
*@**@
@@@*@
@@**@
0 0
样例输出 复制
0
1
2
2
ac代码:
#include<stdio.h>
#include<string.h>
int vis[110][110], m, n, cnt;
char mp[110][110];
int next[8][2] = {-1,0, -1,1, 0,1, 1,1, 1,0, 1,-1, 0,-1, -1,-1};
void dfs(int x, int y) {
// vis[x][y] = 1;
int tx, ty;
for (int k = 0; k < 8; k++) {// 利用循环朝八个方向遍历
//更新变量
tx = x + next[k][0];
ty = y + next[k][1];
//判断边界
if (tx < 1 || tx > m || ty < 0 || ty >= n) continue;
// if (mp[x][y] == '*' || vis[x][y] != 0) continue;
// 这个点必须,没走过 ,并且是油田 ‘@ ’
if (!vis[tx][ty] && mp[tx][ty] == '@') {
vis[tx][ty] = 1;// 标记已经走过了
//向下一个点深搜
dfs(tx, ty);
}
}
return ;
}
int main() {
while (scanf("%d%d", &m, &n) && m && n) {
// getchar();
for(int i = 1; i <= m; i++) {
scanf("%s", mp[i]);// 说明后面要从 第 0 列开始遍历
}
//初始化记号数组 vis
memset(vis, 0, sizeof(vis));
cnt = 0;
for (int i = 1; i <= m; i++) {
for (int j = 0; j < n; j++) {//错误原因: 1,j应该从零开始,因为输入时一次输入一行 默认从第 0 列开始
if (!vis[i][j] && mp[i][j] == '@') {
// vis[i][j] = 1;
dfs(i, j);
cnt++;
}
}
}
printf("%d\n", cnt);
}
}
问题 E: Digit sum
#include <iostream>
//#include <cstring>
#include <cstdio>
using namespace std;
int a[1000005][10];
int main()
{
int T,n,b,tag=0,tmp;
//memset(dp,0,sizeof(dp));
for(int j=2; j<=10; j++){
for(int i=1; i<=1000000; i++){
tmp = i;
while(tmp){
a[i][j] += tmp%j;
tmp/=j;
}
a[i][j] += a[i-1][j];
}
}
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&b);
printf("Case #%d: %d\n",++tag,a[n][b]);
}
return 0;
}
问题 G: 5.5 一山不容二虎
题目描述
在n×n的棋盘上放置彼此不受攻击的n个皇后。按照国际象棋的规则,皇后可以攻击与之在同一行、同一列、同一斜线上的棋子。设计算法在n×n的棋盘上放置n个皇后,使其彼此不受攻击。
输入
样例组数
t ( 0 < t < 20 )
皇后的个数
n ( 0 < n < 20 )
输出
可以摆放的方案总数
ans
样例输入 复制
1
4
样例输出 复制
2
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
#define int long long
#define sc(x) scanf("%lld",&x)
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define lowbit(x) (-x&x)
struct myhash {static uint64_t fxn(uint64_t x) {x += 0x9e3779b97f4a7c15;x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;x = (x ^ (x >> 27)) * 0x94d049bb133111eb;return x ^ (x >> 31);}size_t operator()(uint64_t x) const {static const uint64_t FIXED_RANDOM =chrono::steady_clock::now().time_since_epoch().count();return fxn(x + FIXED_RANDOM);}};
int qmi(int a,int b){int res = 1;while(b){if(b&1){res = res*a;}b = b>>1;a = a*a; } return res;}
int n;
int a[100][100];
int ans = 0;
bool c[100],dui1[100],dui2[100];
void dfs(int x){
if(x>n){
ans++;
return;
}
for(int j=1;j<=n;++j){
int x1 = j-x+n;
int x2 = x+j;
if(c[j]==false&&dui1[x1]==false&&dui2[x2]==false){
c[j] = true;
dui1[x1] = true;
dui2[x2] = true;
dfs(x+1);
c[j] = false;
dui1[x1] = false;
dui2[x2] = false;
}
}
}
void solve()
{
memset(a,0,sizeof a);
ans = 0;
cin>>n;
dfs(1);
cout<<ans<<endl;
}
signed main()
{
//freopen("D:/vsCode/.vscode/oi/in.txt","r",stdin);
//freopen("D:/vsCode/.vscode/oi/out.txt","w",stdout);
IOS
int t = 1;
cin>>t;
while(t--) solve();
return 0;
}
问题 H: 2.4.8.1 集合合并
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, m;
while (cin >> n >> m) {
set<int> s;
for (int i = 0; i < n + m; i++) {
int a;
cin >> a;
s.insert(a);
}
for (auto it = s.begin(); it != s.end(); it++) {
cout << *it << " ";
}
cout << endl;
}
return 0;
}
问题 J: 2.4.9.1 硬木种类
#include <bits/stdc++.h>
using namespace std;
int main() {
map<string, double> mp;
string s;
int cnt = 0;
while (getline(cin, s)) {
mp[s]++;
cnt++;
}
for (auto it = mp.begin(); it != mp.end(); ++it) {
it->second = 1.0 * 100 * it->second / cnt;
cout << it->first << " " << fixed << setprecision(4) << it->second << endl;
}
return 0;
}
问题 K: 2.4.3 骑士移动
题目描述
写程序,计算象棋中马从一个位置移动到另一个位置所需的最少移动次数。
输入
有多组测试数据。
第一行一个整数 T,代表数据组数。
每组数据包含三行。
第一行表示棋盘的长度 L,棋盘大小为 L×L。
第二行包含两个整数 x, y,表示马的起始位置坐标。
第三行包含两个整数 a, b,表示马的终点位置坐标。
L 最大为 300。
棋盘坐标范围为 [0, ..., L-1]。
输出
对于每组数据输出一行,包含一个数字,即最少移动次数。
若起点终点相同,则移动次数为 0。
样例输入 复制
3
8
0 0
7 0
100
0 0
30 50
10
1 1
1 1
样例输出 复制
5
28
0
提示
马走日!!!
数据保证可以到终点,不用额外判断无法走到终点的情况。
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
#define int long long
#define sc(x) scanf("%lld",&x)
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define lowbit(x) (-x&x)
struct myhash {static uint64_t fxn(uint64_t x) {x += 0x9e3779b97f4a7c15;x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;x = (x ^ (x >> 27)) * 0x94d049bb133111eb;return x ^ (x >> 31);}size_t operator()(uint64_t x) const {static const uint64_t FIXED_RANDOM =chrono::steady_clock::now().time_since_epoch().count();return fxn(x + FIXED_RANDOM);}};
int qmi(int a,int b){int res = 1;while(b){if(b&1){res = res*a;}b = b>>1;a = a*a; } return res;}
int sx,sy,ex,ey;
int n;
int dx[8] = {-2,-1,1,2,2,1,-1,-2};
int dy[8] = {1,2,2,1,-1,-2,-2,-1};
bool st[301][301];
int dis[301][301];
int bfs()
{
queue<pair<int,int>> q;
q.push({sx,sy});
dis[sx][sy] = 0;
while(q.size()){
auto t = q.front();
q.pop();
int x = t.first;
int y = t.second;
st[x][y] = true;
for(int i=0;i<8;++i){
x += dx[i]; y+=dy[i];
if(x>=0&&x<=n-1&&y>=0&&y<=n-1&&st[x][y]==false){
q.push({x,y});
st[x][y] = true;
dis[x][y] = dis[x-dx[i]][y-dy[i]]+1;
if(x==ex&&y==ey){
return dis[x][y];
}
}
x-=dx[i];
y-=dy[i];
}
}
}
void solve()
{
memset(st,0,sizeof st);
memset(dis,0x3f,sizeof dis);
cin>>n>>sx>>sy>>ex>>ey;
if(sx==ex&&sy==ey){
cout<<"0"<<endl;
return;
}
cout<<bfs()<<endl;
}
signed main()
{
//freopen("D:/vsCode/.vscode/oi/in.txt","r",stdin);
//freopen("D:/vsCode/.vscode/oi/out.txt","w",stdout);
IOS
int t = 1;
cin>>t;
while(t--) solve();
return 0;
}
问题 L: 衔尾之蚯蚓
题目描述
众所周知,蚯蚓剁成两半之后还能再生,那么重生之后的蚯蚓,它的头和尾是怎么定义的呢?小编也不知道。
现在我们从不大于N的正整数中取出两个数A和B
当A和B以10为基数,并且没有前导零时,A的最后一位数字等于B的第一位,A的第一位数字等于B的最后一位数字。这样就算得上一对合格的蚯蚓(?)
给你一个正整数N,求出这种合格的数对的数量。
输入
N
1≤N≤2×105
输出
符合条件的(A,B)的数量
样例输入 复制
25
样例输出 复制
17
提示
样例说明:
(1,1),(1,11),(2,2),(2,22),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9),(11,1),(11,11),(12,21),(21,12),(22,2),(22,22)
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
#define int long long
#define sc(x) scanf("%lld",&x)
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define lowbit(x) (-x&x)
struct myhash {static uint64_t fxn(uint64_t x) {x += 0x9e3779b97f4a7c15;x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;x = (x ^ (x >> 27)) * 0x94d049bb133111eb;return x ^ (x >> 31);}size_t operator()(uint64_t x) const {static const uint64_t FIXED_RANDOM =chrono::steady_clock::now().time_since_epoch().count();return fxn(x + FIXED_RANDOM);}};
int qmi(int a,int b){int res = 1;while(b){if(b&1){res = res*a;}b = b>>1;a = a*a; } return res;}
void solve()
{
int n; cin>>n;
if(n%10==0) n = n-1;//n能整除10的时候,n这个数字有后缀0无效,为了方便后续的if判断进行-1。
if(n<=9){//特殊处理<=9的情况
cout<<n<<endl;
return;
}
string p = to_string(n);
int maxlen = to_string(n).size();//n的长度
int maxl = p[0] - '0';//n的最高位
int maxr = p[p.size()-1] - '0';//n的最低位
int maxmid = n - maxr - maxl*qmi(10,maxlen-1);//n除去两边两个数之后中间的数字。
int ans = 0;
int leftlen = maxlen - 2;//减去2之后剩余的数位位数。
for(int i=1;i<=n;++i){
if(i%10!=0){
string s = to_string(i);
int l = s[0] - '0';
int r = s[s.size()-1] - '0';//翻转之后r是最高位,l是最低位
if(l==r) ans++;//所以字符一样,多加1,比如222,它可以和数字2首尾相连
if(r*10+l<=n) ans++;//中间不加东西的时候,看本身是否超过n
if(r==maxl){//中间加数字,最高位和n最高位一样
if(l<=maxr){//最低位小于等于n的最低位
ans+=maxmid+1;//根据n的mid中间的数进行加法
if(maxmid==0&&r*100+l>n){//maxmid = 0有两个情况一个是没数字,一个是全是0,这里进行没数字的特殊处理
ans--;
}
}else{
ans+=maxmid;//最低位大于n的最低位,比如28, n = 267,maxmid这时等于6,那么28中间只能插入0~5,6个数字
}
}else if(r<maxl){//最高位小于n的最高位
if(leftlen>0){//剩余位数大于0,比如 n = 267,leftlen = 1,那么就还可以插入一个数字,0~9都可以,也就是10的leftlen次方
ans+=qmi(10,leftlen);
}
}else{
if(leftlen-1>0){//最高位大于n的最高位,那么可以插入的数字只能是leftlen - 1
ans+=qmi(10,leftlen-1);
}
}
}
}
cout<<ans<<endl;
}
signed main()
{
//freopen("D:/vsCode/.vscode/oi/in.txt","r",stdin);
//freopen("D:/vsCode/.vscode/oi/out.txt","w",stdout);
IOS
int t = 1;
//cin>>t;
while(t--) solve();
return 0;
}