第三次双周赛
第一题
题目1
记录每个手指敲击键盘次数
代码1
#include<iostream>
using namespace std;
//记录每个键对应的手指的序号
int a[100];
//每个手指敲击次数
int cnt[9];
int main()
{
a['`'] = 0;
a['1'] = 0;
a['Q'] = 0;
a['A'] = 0;
a['Z'] = 0;
a['2'] = 1;
a['W'] = 1;
a['S'] = 1;
a['X'] = 1;
a['3'] = 2;
a['E'] = 2;
a['D'] = 2;
a['C'] = 2;
a['4'] = 3;
a['R'] = 3;
a['F'] = 3;
a['V'] = 3;
a['5'] = 3;
a['T'] = 3;
a['G'] = 3;
a['B'] = 3;
a['6'] = 4;
a['Y'] = 4;
a['H'] = 4;
a['N'] = 4;
a['7'] = 4;
a['U'] = 4;
a['J'] = 4;
a['M'] = 4;
a['8'] = 5;
a['I'] = 5;
a['K'] = 5;
a[','] = 5;
a['9'] = 6;
a['O'] = 6;
a['L'] = 6;
a['.'] = 6;
a['0'] = 7;
a['P'] = 7;
a[';'] = 7;
a['/'] = 7;
a['-'] = 7;
a['='] = 7;
a['['] = 7;
a[']'] = 7;
a['\''] = 7;
a[' '] = 8;
string s;
cin >> s;
for (char c : s)
{
cnt[a[c]]++;
}
for (int i = 0; i < 8; i++)
{
cout << cnt[i] << endl;
}
return 0;
}
第二题
题目2
有N根相同的香肠,平均分给M个人。问最少需要切多少刀
思路2
逐个切香肠时,需要的刀数最少
代码2
#include<iostream>
using namespace std;
int main()
{
//n、m、刀数
int n, m ,cnt = 0;
cin >> n >> m;
//假设每根香肠长度为m,则每个人分到长度n的香肠
//循环为每个人切
for (int i = 1; i <= m; i++)
{
//前i个人需要的香肠长度如果不是一个香肠长度的整数倍,就说明需要切
if (i * n % m != 0)
{
cnt++;
}
}
cout << cnt << endl;
return 0;
}
第三题
题目3
有很多个活动,这些活动时间会冲突。在同一时间只能安排一个活动,问最多可以安排的活动数量。
思路3
通过贪心来解决。将所有活动按结束时间排序,优先安排结束时间早的活动,这样就能使某段时间内安排的活动数总是最多。最后就能使所有时间内安排的活动数最多,就能得到最多可以安排的活动数量。
代码3
#include<iostream>
#include<algorithm>
using namespace std;
//存放每个活动的结构体,包含了开始时间和结束时间,并声明一个活动的数组
struct event
{
int start, end;
} events[10000];
int main()
{
int m;
cin >> m;
//循环处理多组数据
for (int i = 0; i < m; i++)
{
//活动数和最多可以安排的活动的数量
int n, cnt = 0;
cin >> n;
for (int j = 0; j < n; j++)
{
cin >> events[j].start >> events[j].end;
}
//按照结束事件升序排序(通过Lambda表达式)
sort(events, events + n, [](event left, event right){return left.end < right.end; });
//假设当前的时间,初始为0
int now = 0;
//遍历所有活动(按结束时间升序)
for (int j = 0; j < n; j++)
{
//如果当前时间这个活动还没开始,就可以安排这个活动
if (now <= events[j].start)
{
cnt++;
//更新当前的时间
now = events[j].end;
}
}
cout << cnt << endl;
}
return 0;
}
第四题
题目4
解密一种密码。改密码将重复的字符串X以"[DX]"的形式存储,表示字符串X出现了D次。同时该规则可以嵌套,如:CBCBCBCB = [4CB] = [2[2CB]]。
思路4
可以使用递归解决。编写一个函数处理单个的"[]“,当函数再遇到”[]“就递归调用,处理内部的”[]“。处理结束后,将”[]"完整的字符串返回给上一级,再串成解密后的字符串。
代码4
#include<iostream>
using namespace std;
string getString()
{
//用于存储读取到的字符
char c;
//[DX]中的D
int n;
//结果
string r;
while (cin >> c)
{
//内部的[],则递归
if (c == '[')
{
//获取内部[]中的D
cin >> n;
//获得内部[]中的X
string sub = getString();
//将X重复D遍
while (n--)
{
r += sub;
}
}
//括号的结束,返回字符串
else if (c == ']')
{
return r;
}
//是字符则加入结果字符串
else
{
r += c;
}
}
//没有括号时的返回
return r;
}
int main()
{
cout << getString();
return 0;
}
第五题
题目5
有n个大臣,左右手各有一个数字;有一个国王,左右手也各有一个数字。国王站在最前面,大臣以某中方式排列再国王后。每个大臣可以获得他前面每个人左手上的数的乘积再除以他右手上的数的奖赏。问怎么排列才能使获得奖赏最多的大臣的奖赏最少。
思路5
比较两个大臣谁在前谁在后的方法:如果有两个大臣A和B,A前面的有其他大臣。如果A的左手数字除以B的右手数字大于B的左手数字除以A的右手数字,则当A站在B前时,AB两个人靠后的那个人(B)得到的钱最大。如果反过来,A站在B后,AB两个人靠后的那个人(A)得到的钱就会比前一种情况少。因此可以依据一个人左手数字除以另一个人右手数字的大小来安排两个大臣的前后顺序,也就是按照一个人左右手数字的乘积的大小来安排大臣的前后顺序。
通过上面的方法对所有大臣排序后,这个序列就是最佳序列,只需要找到奖赏最多的大臣就能得到答案。
由于涉及大量整数的乘积,很容易超过范围,所以还需要使用高精。
代码5
#include<iostream>
#include<utility>
#include<vector>
#include<algorithm>
using namespace std;
//存储每个大臣左右手的数字
pair<int, int> ab[1000];
//高精的结构体,便于主函数的操作,同时练习一下课程刚学的运算符
struct High
{
//每一位的数字
vector<int> places;
//运算符*,计算一个高精数乘以一个int
High operator* (const int& number)
{
//结果
High r;
//暂存当前的进位结果
int n = 0;
for (int i = 0; i < places.size(); i++)
{
n += places[i] * number;
r.places.push_back(n % 10);
n /= 10;
}
//将超出原位数的位存入结果数
while (n != 0)
{
r.places.push_back(n % 10);
n /= 10;
}
//去0
while (r.places.back() == 0 && r.places.size() > 1)
{
r.places.pop_back();
}
return r;
}
//运算符/,用于计算高精除int
High operator/(const int& number)
{
//结果
High r;
//当前从上一位剩余的数
int n = 0;
//除法从高位往低位进行
for (int i = places.size() - 1; i >= 0; i--)
{
n *= 10;
n += places[i];
r.places.push_back(n / number);
//求余数
n %= number;
}
//这样得到的数每一位是过来的,需要反转
reverse(r.places.begin(), r.places.end());
//去0
while (r.places.back() == 0 && r.places.size() > 1)
{
r.places.pop_back();
}
return r;
}
//运算符>,比较两个高精数的大小
bool operator>(const High& number)
{
//位数不同时,位数大的大
if (number.places.size() != places.size())
{
return places.size() > number.places.size();
}
//位数相同时,从高位开始逐个判断
else
{
for (int i = places.size() - 1; i >= 0; i--)
{
if (places[i] != number.places[i])
{
return places[i] > number.places[i];
}
}
return false;
}
}
//无参构造函数
High(){}
//用一个int初始化高精
High(int n)
{
while (n != 0)
{
places.push_back(n % 10);
n /= 10;
}
}
//运算符<<,用于输出高精数
friend ostream& operator<<(ostream& out, High& high)
{
for (int i = high.places.size() - 1; i >= 0; i--)
{
out << high.places[i];
}
return out;
}
};
int main()
{
//大臣数、国王左手数、国王右手数
int n, a, b;
//结果
High ans;
cin >> n >> a >> b;
for (int i = 0; i < n; i++)
{
int aa, bb;
cin >> aa >> bb;
ab[i] = make_pair(aa, bb);
}
//对大臣排序,规则为上述规则
sort(ab, ab + n, [](pair<int, int> left, pair<int, int> right){return left.first * left.second < right.first * right.second;});
//给答案设置初始值为第一个大臣的奖赏
ans = High(a / ab[0].second);
//当前大臣前面所有人左手数乘积
High h(a);
//遍历第二个大臣开始的所有大臣
for (int i = 1; i < n; i++)
{
//更新乘积
h = h * ab[i - 1].first;
//这个大臣的奖赏
High m = h / ab[i].second;
//更新答案
if (m > ans)
{
ans = m;
}
}
cout << ans << endl;
return 0;
}