第一次双周赛
第一题 重要的话说三遍
代码1
#include<iostream>
using namespace std;
int main()
{
cout << "I'm gonna WIN!" << endl;
cout << "I'm gonna WIN!" << endl;
cout << "I'm gonna WIN!" << endl;
return 0;
}
第二题 日期格式化
代码2
#include<iostream>
using namespace std;
int main()
{
string s;
cin >> s;
cout << s.substr(6, 4) << "-" << s.substr(0, 2) << "-" << s.substr(3,2) << endl;
return 0;
}
第三题 大笨钟
题目3
0 − 12 0 - 12 0−12 点不敲钟, 13 − 24 13 - 24 13−24 敲 1 − 12 1 - 12 1−12 下。过了整点就敲下一个整点数。
代码3
#include<iostream>
#include<iomanip>
using namespace std;
int main()
{
int h, m;
char t;
cin >> h >> t >> m;
//0-12点(包含端点)
if ((h >= 0 && h < 12) || (h == 12 && m == 0))
{
cout << "Only " << setfill('0') << setiosflags(ios::right) << setw(2)<< h << ":" << setfill('0') << setiosflags(ios::right) << setw(2) << m << ". Too early to Dang." << endl;
}
//其余时间
else
{
for (int i = 0; i < (m == 0 ? h : h + 1) - 12; i++)
{
cout << "Dang";
}
cout << endl;
}
return 0;
}
第四题 拯救外星人
题目4
给出 A A A 和 B B B 求 ( A + B ) ! (A + B)! (A+B)!
代码4
#include<iostream>
using namespace std;
int main()
{
long long a, b;
cin >> a >> b;
long long r = 1;
for (int i = 1; i <= a + b; i++)
{
r *= i;
}
cout << r << endl;
return 0;
}
第五题 个位数统计
题目5
统计一个数字中 0 − 9 0 - 9 0−9 各个数字出现的次数。
思路5
创建一个数组存储每一个数字出现的次数。
代码5
#include<iostream>
using namespace std;
int main()
{
//读取字符串更方便处理
string s;
cin >> s;
//存储每一个数字出现的次数
int f[10] = {};
for (int i = 0; i < (int)s.size(); i++)
{
f[s[i] - '0']++;
}
for (int i = 0; i <10; i++)
{
//出现0次不需要输出
if (f[i] != 0)
{
cout << i << ":" << f[i] << endl;
}
}
return 0;
}
第六题 正整数A+B
题目6
求 A + B A + B A+B 的值。但是 A A A 和 B B B 可能为任何字符。如果不是满足要求的正整数则用 ? ? ? 表示。
思路6
因为不保证 B B B 中没有空格,所以需要读取一整行,从读取的字符串中寻找第一个空格,将其分割成 A A A 和 B B B 即可。
代码6
#include<iostream>
using namespace std;
//处理 A 和 B,不符合要求的返回-1
int process(string& s)
{
int n = 0;
//空字符串不符合二要求
if (s.size() == 0)
{
return -1;
}
//遍历每一个字符
for (int i = 0; i < (int)s.size(); i++)
{
//每一位都是数字
if (s[i] >= '0' && s[i] <= '9')
{
n *= 10;
n += s[i] - '0';
}
else
{
return -1;
}
}
//正整数不在范围内
return (n < 1 || n > 1000) ? -1 : n;
}
int main()
{
//缓冲区
char s[1024 * 1024];
//字符串A和B
string s1, s2;
//获取一行
cin.getline(s, sizeof(s));
//寻找第一个空格
for (int i = 0; ; i++)
{
if (s[i] == ' ')
{
//分割A和B
s1 = string(s, 0, i);
s2 = string(s + i + 1);
break;
}
}
//A的处理结果和B的处理结果
int n1, n2;
n1 = process(s1);
n2 = process(s2);
//小于0代表不符合要求,输出?
if (n1 < 0)
{
cout << "? + ";
}
else
{
cout << n1 << " + ";
}
if (n2 < 0)
{
cout << "? = ";
}
else
{
cout << n2 << " = ";
}
//如果A或B不符合要求,结果就是?
if (n1 < 0 || n2 < 0)
{
cout << "?" << endl;
}
else
{
cout << n1 + n2 << endl;
}
return 0;
}
第七题 打印沙漏
题目7
要求写个程序把给定的符号打印成沙漏的形状。需要用最多的给定字符。
思路7
先找到能使用的最多的字符和这些字符能打印的行数,然后按照行数打印。
代码7
#include<iostream>
using namespace std;
int main()
{
//n,使用的字符数
int n ,cnt = 0;
char c;
cin >> n >> c;
//i代表行数,t代表当前使用的字符数
int i, t = 1;
//从第一行开始累计使用的字符数(不包括单个字符的那一行,其余行都出现两次)
for (i = 1; t < n; i++)
{
t += 2 * (2 * i + 1);
}
//减去循环最后一次的累加
i--;
//如果使用的字符数超了,那么行数还需要减一
if (t != n)
{
i--;
}
//打印上半部分
for (int j = i; j > 0; j--)
{
//打印空格
for (int k = 0; k < (i - j); k++)
{
cout << ' ';
}
//打印字符
for (int k = 0; k < 2 * j + 1; k++)
{
cout << c;
cnt++;
}
cout << endl;
}
//打印单个字符的行
for (int k = 0; k < i; k++)
{
cout << ' ';
}
cout << c << endl;
cnt++;
//打印下半部分
for (int j = 1; j <= i; j++)
{
for (int k = 0; k < (i - j); k++)
{
cout << ' ';
}
for (int k = 0; k < 2 * j + 1; k++)
{
cout << c;
cnt++;
}
cout << endl;
}
//打印未使用的字符个数
cout << n - cnt << endl;
return 0;
}
第八题 机工士姆斯塔迪奥
题目8
有一个 N × M N \times M N×M 的地图,选择若干行和列,问剩下未被选择的格子数量。
思路8
无论选择哪一行或列,都可以将其任意平移至未被选择的行或列。经过平移,最后可以得到一块矩形的未被选择的多个格子。
代码8
#include<iostream>
using namespace std;
constexpr int maxmn = 1e5 + 5;
//记录被占用的列和行
bool cvis[maxmn], rvis[maxmn];
int main()
{
long long n, m, q;
cin >> n >> m >> q;
long long rcnt = 0, ccnt = 0;
while (q--)
{
int ti, ci;
cin >> ti >> ci;
if (ti == 0)
{
if (!rvis[ci])
{
rvis[ci] = true;
rcnt++;
}
}
else
{
if (!cvis[ci])
{
cvis[ci] = true;
ccnt++;
}
}
}
//计算结果
long long cnt = (n - rcnt) * (m - ccnt);
cout << cnt << endl;
return 0;
}
第九题 排座位
题目9
有
N
N
N 个人,给出这些人间的一些关系:朋友和敌人。朋友也是朋友,但敌人的敌人并不一定就是朋友,朋友的敌人也不一定是敌人。
如果两位宾客之间是朋友,且没有敌对关系,则输出No problem;如果他们之间并不是朋友,但也不敌对,则输出OK;如果他们之间有敌对,然而也有共同的朋友,则输出OK but…;如果他们之间只有敌对关系,则输出No way。
思路9
由于朋友的朋友也是朋友,所以要先算出所有人之间是否为简介的朋友。借鉴Floyd算法的思想,可以通过“中转”的方法得到两个人是否为间接的朋友。
代码9
#include<iostream>
using namespace std;
constexpr int maxn = 101;
int n, m, k;
//题目给出的原来的关系
int re[maxn][maxn];
//是否为间接或直接的朋友
int fr[maxn][maxn];
int main()
{
cin >> n >> m >> k;
//输入题目的关系
while (m--)
{
int g1, g2, r;
cin >> g1 >> g2 >> r;
re[g1][g2] = r;
re[g2][g1] = r;
fr[g1][g2] = r;
fr[g2][g1] = r;
}
//计算任意两个人之间是否为朋友
//i和j是否为朋友,通过kk中转
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
for (int kk = 1; kk <= n; kk++)
{
if (fr[i][kk] == 1 && fr[kk][j] == 1)
{
fr[i][j] = 1;
}
}
}
}
while (k--)
{
int g1, g2;
cin >> g1 >> g2;
//是直接的朋友或者是间接的朋友
if (re[g1][g2] == 1 || (fr[g1][g2] == 1 && re[g1][g2] != -1))
{
cout << "No problem" << endl;
}
//没有直接关系也不是间接的朋友
else if (re[g1][g2] == 0 && fr[g1][g2] != 1)
{
cout << "OK" << endl;
}
//是敌人但有间接的朋友
else if (re[g1][g2] == -1 && fr[g1][g2] == 1 )
{
cout << "OK but..." << endl;
}
//是敌人
else
{
cout << "No way" << endl;
}
}
return 0;
}
第十题 名人堂与代金券
题目10
总评成绩必须达到
60
60
60 分及以上,并且有另加福利:总评分在
[
G
,
100
]
[G, 100]
[G,100] 区间内者,可以得到
50
50
50 元 PAT 代金券;在
[
60
,
G
)
[60, G)
[60,G) 区间内者,可以得到
20
20
20 元PAT代金券。同时任课老师还会把总评成绩前 K 名的学生列入课程“名人堂”。
列出名人堂的学生,并统计一共发出了面值多少元的 PAT 代金券。
思路10
简单的模拟。按题目要求累计和排序。
代码10
#include<iostream>
#include<algorithm>
using namespace std;
constexpr int maxn = 10000 + 5;
//total是所有 PAT 代金券面值
int n, g, k, total;
//记录学生
struct student
{
//账号名
string account;
//分数和排序
int score, rank;
} s[maxn];
int main()
{
cin >> n >> g >> k;
for (int i = 1; i <= n; i++)
{
cin >> s[i].account >> s[i].score;
//累加面值
if (s[i].score <= 100 && s[i].score >= g)
{
total += 50;
}
else if (s[i].score < g && s[i].score >= 60)
{
total += 20;
}
}
cout << total << endl;
//先按照分数排序
sort(s + 1, s + n + 1, [](student& left, student& right){ return left.score > right.score; });
//同分数的再按照账号名排序,并同时记录排名
//rank是当前的排名
int rank = 0, nowscore = 0x3f3f3f3f, samestart = 0;
for (int i = 1; i <= n; i++)
{
//分数变了之后,对前一组同分进行排序,并更新当前的排名位置
if (nowscore != s[i].score)
{
sort(s + samestart, s + i, [](student& left, student& right){ return left.account < right.account; });
samestart = i;
rank = i;
nowscore = s[i].score;
}
s[i].rank = rank;
}
sort(s + samestart, s + n + 1, [](student& left, student& right){ return left.account < right.account; });
//输出排名
int i = 1;
while (s[i].rank <= k && i <= n)
{
cout << s[i].rank << ' ' << s[i].account << ' ' << s[i].score << endl;
i++;
}
return 0;
}
第十一题 包装机
题目11
机器中有
N
N
N 条轨道,放置了一些物品。轨道下面有一个筐。当某条轨道的按钮被按下时,活塞向左推动,将轨道尽头的一件物品推落筐中。当
0
0
0 号按钮被按下时,机械手将抓取筐顶部的一件物品,放到流水线上。
筐的容量是有限的,当筐已经满了,但仍然有某条轨道的按钮被按下时,系统应强制启动 0 号键,先从筐里抓出一件物品,再将对应轨道的物品推落。此外,如果轨道已经空了,再按对应的按钮不会发生任何事;同样的,如果筐是空的,按
0
0
0 号按钮也不会发生任何事。
给定一系列按钮操作,依次列出流水线上的物品。
思路11
这是一道栈的模拟题。定义一个栈然后模拟操作。
代码11
#include<iostream>
#include<stack>
using namespace std;
constexpr int maxm = 1001, maxn = 101;
int n, m,smax, scnt;
//所有轨道
stack<char> track[maxn];
//框
stack<char> s;
int main()
{
cin >> n >> m >> smax;
for (int i = 1; i <= n; i++)
{
string t;
cin >> t;
//倒序将轨道上的物品放到轨道上
for (int j = (int)t.size() - 1; j >= 0; j--)
{
track[i].push(t[j]);
}
}
while (true)
{
int o;
cin >> o;
//-1代表中止
if (o == -1)
{
break;
}
//0代表抓取筐顶部的一件物品
if (o == 0)
{
//先判断是否为空
if (!s.empty())
{
cout << s.top();
s.pop();
scnt--;
}
}
//其余情况是轨道的按钮
else
{
//先判断是否为空
if (!track[o].empty())
{
//框满了,就执行0的操作
if (scnt == smax)
{
cout << s.top();
s.pop();
scnt--;
}
//入框
s.push(track[o].top());
scnt++;
track[o].pop();
}
}
}
return 0;
}
第十二题 愿天下有情人都是失散多年的兄妹
题目12
给出家族关系,判断两人是否五服以内。
思路12
可以分别列出两人五服以内所有人,然后判断是否有人同时出现在两组中。
代码12
#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
constexpr int maxn = 1e5 + 5;
int n, k;
//两个人五代以内所有亲属的id
vector<int> id1All, id2All;
//记录每个人的信息
struct person
{
//性别
char gender;
//父亲和母亲的id
int father = 0, mother = 0;
} people[maxn];
//dfs搜索某人五代以内亲属
void dfs(int step, int id, vector<int>& result)
{
//向上搜索到第四代中止
if (step == 4)
{
return;
}
//父亲有记录,就存进vector
if (people[id].father > 0)
{
result.push_back(people[id].father);
dfs(step + 1, people[id].father, result);
}
//母亲有记录,就存进vector
if (people[id].mother > 0)
{
result.push_back(people[id].mother);
dfs(step + 1, people[id].mother, result);
}
}
//寻找某人五代以内所有亲属
void findAll(int id, vector<int>& result)
{
result.push_back(id);
dfs(0, id, result);
}
int main()
{
cin >> n;
for (int i = 1; i <= n; i++)
{
int id;
cin >> id;
cin >> people[id].gender >> people[id].father >> people[id]. mother;
//父亲一定是男性
if (people[id].father > 0)
{
people[people[id].father].gender = 'M';
}
//母亲一定是女性
if (people[id].mother > 0)
{
people[people[id].mother].gender = 'F';
}
}
cin >> k;
while (k--)
{
int id1, id2;
cin >> id1 >> id2;
//同性
if (people[id1].gender == people[id2].gender)
{
cout << "Never Mind" << endl;
}
else
{
//清除上次的记录
id1All.clear();
id2All.clear();
//查找
findAll(id1, id1All);
findAll(id2, id2All);
//标记是否有同时出现在两组之中的人
bool exist = false;
for (int i = 0; i < (int)id1All.size(); i++)
{
for (int j = 0; j < (int)id2All.size(); j++)
{
if (id1All[i] == id2All[j])
{
exist = true;
break;
}
}
}
cout << (exist ? "No" : "Yes") << endl;
}
}
return 0;
}