目录
- 1081 Rational Sum (20分)
- 1082 Read Number in Chinese (25分) 推荐:1星
- 1083 List Grades (25分)
- 1084 Broken Keyboard (20分)
- 1085 Perfect Sequence (25分)
- 1086 Tree Traversals Again (25分) 推荐指数:1星
- 1087 All Roads Lead to Rome (30分) 推荐:★
- 1088 Rational Arithmetic (20分) 推荐:★
- 1089 Insert or Merge (25分) ★★★
- 1090 Highest Price in Supply Chain (25分)
1081 Rational Sum (20分)
题目
Sample Input 1:
5
2/5 4/15 1/30 -2/60 8/3
Sample Output 1:
3 1/3
Sample Input 2:
2
4/3 2/3
Sample Output 2:
2
Sample Input 3:
3
1/3 -1/6 1/8
Sample Output 3:
7/24
题解
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
long long gcd(long long a, long long b) {
return b == 0 ? abs(a) : gcd(b, a%b);
}
int main() {
#ifndef ONLINE_JUDGE
freopen("data.txt", "r", stdin);
#endif
long long n, a, b, suma = 0, sumb = 1, gcdvalue;
scanf("%lld", &n);
for (int i = 0; i < n; ++i) {
scanf("%lld/%lld", &a, &b);
gcdvalue = gcd(a, b);
a = a / gcdvalue;
b = b / gcdvalue;
suma = a * sumb + suma *b;
sumb = b * sumb;
gcdvalue = gcd(suma, sumb);
suma /= gcdvalue;
sumb /= gcdvalue;
}
long long integer = suma / sumb;
suma = suma - (sumb * integer);
if (integer != 0) {
printf("%lld", integer);
if (suma != 0) printf(" ");
}
if (suma != 0)
printf("%lld/%lld", suma, sumb);
if (integer == 0 && suma == 0)
printf("0");
return 0;
}
1082 Read Number in Chinese (25分) 推荐:1星
题目
Sample Input 1:
-123456789
Sample Output 1:
Fu yi Yi er Qian san Bai si Shi wu Wan liu Qian qi Bai ba Shi jiu
Sample Input 2:
100800
Sample Output 2:
yi Shi Wan ling ba Bai
分析
推荐:1星
模拟题,重点在输出 “ling"的条件判断。
题解
#include <stdio.h>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
string num[10] = { "ling","yi", "er", "san", "si", "wu", "liu", "qi", "ba", "jiu" };
string c[6] = { "Ge","Shi", "Bai", "Qian", "Yi", "Wan" };
int J[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 };
vector<string> res;
int main() {
#ifndef ONLINE_JUDGE
freopen("data.txt", "r", stdin);
#endif
int n;
cin >> n;
if (n == 0) {
cout << "ling";
return 0;
}
if (n < 0) {
cout << "Fu ";
n = -n;
}
int part[3];
part[0] = n / 100000000;
part[1] = (n % 100000000) / 10000;
part[2] = n % 10000;
bool zero = false; //是否在非零数字前输出合适的ling
int printCnt = 0; //用于维护单词前没有空格,之后输入的单词都在前面加一个空格。
for (int i = 0; i < 3; i++) {
int temp = part[i]; //三个部分,每部分内部的命名规则都一样,都是X千X百X十X
for (int j = 3; j >= 0; j--) {
int curPos = 8 - i * 4 + j; //当前数字的位置
if (curPos >= 9) continue; //最多九位数
int cur = (temp / J[j]) % 10;//取出当前数字
if (cur != 0) {
if (zero) {
printCnt++ == 0 ? cout << "ling" : cout << " ling";
zero = false;
}
if (j == 0)
printCnt++ == 0 ? cout << num[cur] : cout << ' ' << num[cur]; //在个位,直接输出
else
printCnt++ == 0 ? cout << num[cur] << ' ' << c[j] : cout << ' ' << num[cur] << ' ' << c[j]; //在其他位,还要输出十百千
}
else {
if (!zero&&j != 0 && n / J[curPos] >= 10) zero = true; //注意100020这样的情况
}
}
if (i != 2 && part[i]>0) cout << ' ' << c[i + 4]; //处理完每部分之后,最后输出单位,Yi/Wan
}
return 0;
}
1083 List Grades (25分)
题目
Sample Input 1:
4
Tom CS000001 59
Joe Math990112 89
Mike CS991301 100
Mary EE990830 95
60 100
Sample Output 1:
Mike CS991301
Mary EE990830
Joe Math990112
Sample Input 2:
2
Jean AA980920 60
Ann CS01 80
90 95
Sample Output 2:
NONE
分析
模拟题
题解
#include <stdio.h>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
struct stu {
char name[12];
char id[12];
int grade;
};
bool cmp1(stu a, stu b) {
return a.grade > b.grade;
}
int main() {
#ifdef ONLINE_JUDGE
#else
freopen("data.txt", "r", stdin);
#endif // ONLINE_JUDGE
int n, low, high, cnt = 0;
scanf("%d", &n);
vector<stu> v(n);
for (int i = 0; i < n; ++i) {
scanf("%s %s %d", v[i].name, v[i].id, &v[i].grade);
}
scanf("%d %d", &low, &high);
for (int i = 0; i < n; ++i) {
if (v[i].grade < low || v[i].grade > high) {
v[i].grade = -1;
}
else {
++cnt;
}
}
sort(v.begin(), v.end(), cmp1);
for (int i = 0; i < cnt; ++i) {
printf("%s %s\n", v[i].name, v[i].id);
}
if (cnt == 0) {
printf("NONE");
}
return 0;
}
1084 Broken Keyboard (20分)
题目
Sample Input:
7_This_is_a_test
_hs_s_a_es
Sample Output:
7TI
分析
利用STL库可以更快地写出你的代码,当然只要能解出来,用什么都行。
题解
使用stl
#include <iostream>
#include <cctype>
using namespace std;
int main() {
#ifndef ONLINE_JUDGE
freopen("data.txt", "r", stdin);
#endif // ONLINE_JUDGE
string s1, s2, ans;
cin >> s1 >> s2;
for (int i = 0; i < s1.length(); i++)
if (s2.find(s1[i]) == string::npos && ans.find(toupper(s1[i])) == string::npos)
ans += toupper(s1[i]);
cout << ans;
return 0;
}
不使用std(打表)
#include <iostream>
#include <string>
#include <string.h>
using namespace std;
bool book[256];
int main(){
#ifndef ONLINE_JUDGE
freopen("data.txt", "r", stdin);
#endif // ONLINE_JUDGE
string s1, s2;
cin >> s1 >> s2;
for(int i = 0; i < s2.length(); i++) book[toupper(s2[i])] = true;
for(int i = 0; i < s1.length(); i++){
char t = toupper(s1[i]);
if(!book[t]){
book[t] = true;
printf("%c", t);
}
}
return 0;
}
1085 Perfect Sequence (25分)
题目
Sample Input:
10 8
2 3 20 4 5 1 6 7 8 9
Sample Output:
8
分析
这道题目看似平平无奇,事实上隐藏着一个剪枝的小技巧,如果不进行只是使用循环的话,可能会超时。
要点
转换下思路,利用前面的结果来剪枝,先进行排序,使用result来保存之前最长的长度,后面就可以直接从i+result开始,跳过result个之前比较过的值。
知识点
- 使用尽可能多的数组成符合 M < N * q的数组
- N是最小,M是最大
题解
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main(){
int n;
long long p;
scanf("%d%lld", &n, &p);
vector<int> v(n);
for (int i = 0; i < n; i++)
cin >> v[i];
sort(v.begin(), v.end()); ///对顺序没要求就应该先排序
int result = 0, temp = 0;
for (int i = 0; i < n; i++) {
for (int j = i + result; j < n; j++) {
if (v[j] <= v[i] * p) {
temp = j - i + 1;
if (temp > result) ///result
result = temp;
} else {
break;
}
}
}
cout << result;
return 0;
}
1086 Tree Traversals Again (25分) 推荐指数:1星
题目
Sample Input:
6
Push 1
Push 2
Push 3
Pop
Pop
Push 4
Pop
Pop
Push 5
Push 6
Pop
Pop
Sample Output:
3 4 2 6 5 1
分析
题目给人的感觉似乎是要做一道模拟堆栈的题,但是,你要是这么做,就too young too simple了,实际上,这是一道前序+中序得后序的题目。有前序来提供root节点,由中序来划分左右
要点
- 前序,中序数组转后序 : 注意到前序的存在很关键
- 模拟栈处理
题解
#include <cstdio> ///等价于stdio.h
#include <vector>
#include <stack>
#include <cstring>
using namespace std;
vector<int> pre, in, post,value; ///数组中保留的是下标
void postorder(int root, int start, int end) { ///后序排列
if (start > end) return;
int i = start;
while (i < end && in[i] != pre[root]) i++;
postorder(root + 1, start, i - 1);
postorder(root + 1 + i - start, i + 1, end);
post.push_back(pre[root]);
}
int main() {
int n;
scanf("%d", &n);
char str[5];
stack<int> s;
int key=0;
while (~scanf("%s", str)) { ///遍历数组,并生成inorder的数组
if (strlen(str) == 4) {
int num;
scanf("%d", &num);
value.push_back(num);
pre.push_back(key);
s.push(key++);
} else {
in.push_back(s.top());
s.pop();
}
}
postorder(0, 0, n - 1);
printf("%d", value[post[0]]);
for (int i = 1; i < n; i++)
printf(" %d",value[post[i]]);
return 0;
}
1087 All Roads Lead to Rome (30分) 推荐:★
题目
Sample Input:
6 7 HZH
ROM 100
PKN 40
GDN 55
PRS 95
BLN 80
ROM GDN 1
BLN ROM 1
HZH PKN 1
PRS ROM 2
BLN HZH 2
PKN GDN 1
HZH PRS 1
Sample Output:
3 3 195 97
HZH->PRS->ROM
分析
这种题型的重要性不用多说,再来巩固一下吧。
注意查找路径得通过dfs,在抵达目标后进行一些决策即可判断。
知识点
- 最短路径问题
- 深度搜索
- 模拟
- 名称映射
题解
#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
using namespace std;
int n, k;
const int inf = 999999999;
int e[205][205], weight[205], dis[205];
bool visit[205];
vector<int> pre[205], temppath, path;
map<string, int> m;
map<int, string> m2;
int maxvalue = 0, mindepth, cntpath = 0;
double maxavg;
void dfs(int v) { ///当前点进入路径
temppath.push_back(v);
if(v == 1) {
int value = 0;
for(int i = 0; i < temppath.size(); i++) {
value += weight[temppath[i]];
}
double tempavg = 1.0 * value / (temppath.size() - 1);
if(value > maxvalue) {
maxvalue = value;
maxavg = tempavg;
path = temppath;
} else if(value == maxvalue && tempavg > maxavg) {
maxavg = tempavg;
path = temppath;
}
temppath.pop_back();
cntpath++;
return ;
}
for(int i = 0; i < pre[v].size(); i++) {
dfs(pre[v][i]);
}
temppath.pop_back();
}
int main() {
fill(e[0], e[0] + 205 * 205, inf);
fill(dis, dis + 205, inf);
scanf("%d %d", &n, &k);
string s;
cin >> s;
m[s] = 1;/// 1 : 目的城市
m2[1] = s;
for(int i = 1; i < n; i++) {
cin >> s >> weight[i+1];
m[s] = i+1;
m2[i+1] = s;
}
string sa, sb;
int temp;
for(int i = 0; i < k; i++) {
cin >> sa >> sb >> temp;
e[m[sa]][m[sb]] = temp;
e[m[sb]][m[sa]] = temp;
}
dis[1] = 0;
for(int i = 0; i < n; i++) {
int u = -1, minn = inf;
for(int j = 1; j <= n; j++) {
if(visit[j] == false && dis[j] < minn) {
u = j;
minn = dis[j];
}
}
if(u == -1) break;
visit[u] = true;
for(int v = 1; v <= n; v++) { ///第一遍遍历
if(visit[v] == false && e[u][v] != inf) {
if(dis[u] + e[u][v] < dis[v]) {
dis[v] = dis[u] + e[u][v];
pre[v].clear();
pre[v].push_back(u);
} else if(dis[v] == dis[u] + e[u][v]) {
pre[v].push_back(u);
}
}
}
}
int rom = m["ROM"];
dfs(rom); ///从后往前
printf("%d %d %d %d\n", cntpath, dis[rom], maxvalue, (int)maxavg);
for(int i = path.size() - 1; i >= 1; i--) { ///反向输出
cout << m2[path[i]] << "->";
}
cout << "ROM";
return 0;
}
1088 Rational Arithmetic (20分) 推荐:★
题目
Sample Input 1:
2/3 -4/2
Sample Output 1:
2/3 + (-2) = (-1 1/3)
2/3 - (-2) = 2 2/3
2/3 * (-2) = (-1 1/3)
2/3 / (-2) = (-1/3)
Sample Input 2:
5/3 0/6
Sample Output 2:
1 2/3 + 0 = 1 2/3
1 2/3 - 0 = 1 2/3
1 2/3 * 0 = 0
1 2/3 / 0 = Inf
分析
涉及到整型的运算,注意使用longlong类型的数据
- 很多的小细节
- 找最小公约数
题解
#include <iostream>
#include <cmath>
using namespace std;
long long a, b, c, d;
long long gcd(long long t1, long long t2) { ///先找最小公约数
return t2 == 0 ? t1 : gcd(t2, t1 % t2);
}
void func(long long m, long long n) { ///利用这个来输出单个数,最小粒度,最快实现
if (m * n == 0) {
printf("%s", n == 0 ? "Inf" : "0");
return ;
}
bool flag = ((m < 0 && n > 0) || (m > 0 && n < 0));
m = abs(m); n = abs(n);
long long x = m / n;
printf("%s", flag ? "(-" : "");
if (x != 0) printf("%lld", x);
if (m % n == 0) {
if(flag) printf(")");
return ;
}
if (x != 0) printf(" ");
m = m - x * n;
long long t = gcd(m, n);
m = m / t; n = n / t;
printf("%lld/%lld%s", m, n, flag ? ")" : "");
}
int main() {
scanf("%lld/%lld %lld/%lld", &a, &b, &c, &d);
func(a, b); printf(" + "); func(c, d); printf(" = "); func(a * d + b * c, b * d); printf("\n");
func(a, b); printf(" - "); func(c, d); printf(" = "); func(a * d - b * c, b * d); printf("\n");
func(a, b); printf(" * "); func(c, d); printf(" = "); func(a * c, b * d); printf("\n");
func(a, b); printf(" / "); func(c, d); printf(" = "); func(a * d, b * c);
return 0;
}
1089 Insert or Merge (25分) ★★★
题目
Sample Input 1:
10
3 1 2 8 7 5 9 4 6 0
1 2 3 7 8 5 9 4 6 0
Sample Output 1:
Insertion Sort
1 2 3 5 7 8 9 4 6 0
Sample Input 2:
10
3 1 2 8 7 5 9 4 0 6
1 3 2 8 5 7 4 9 0 6
Sample Output 2:
Merge Sort
1 2 3 8 4 5 7 9 0 6
分析
插入排序:
分块排序:很有意思k*2思路,要点多多,十分有趣
排序一些技巧
注意分部的时候:i < n/k
题解
判断是插入排序还是合并排序,并返回下一次操作后的值
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
int n, a[100], b[100], i, j;
cin >> n;
for (int i = 0; i < n; i++)
cin >> a[i]; ///原始数组
for (int i = 0; i < n; i++)
cin >> b[i]; ///部分排序数组
for (i = 0; i < n - 1 && b[i] <= b[i + 1]; i++); ///获取部分排序数组的有序部分
for (j = i + 1; a[j] == b[j] && j < n; j++); ///判断无序部分相同的位置
if (j == n) { ///与数组长度相同
cout << "Insertion Sort" << endl; ///插入排序
sort(a, a + i + 2); ///左开右闭,返回下一次排序的结果,即排序到 i+1位置
} else {
cout << "Merge Sort" << endl; ///合并排序
int k = 1, flag = 1;
while(flag) { /// 一步步排序,直到完全相等
flag = 0;
for (i = 0; i < n; i++) {
if (a[i] != b[i])
flag = 1;
}
k = k * 2;
for (i = 0; i < n / k; i++)
sort(a + i * k, a + (i + 1) * k); ///使用sort来代劳
sort(a + n / k * k, a + n);
}
}
for (j = 0; j < n; j++) {
if (j != 0) printf(" ");
printf("%d", a[j]);
}
return 0;
}
1090 Highest Price in Supply Chain (25分)
题目
Sample Input:
9 1.80 1.00
1 5 4 4 -1 4 5 3 6
Sample Output:
1.85 2
分析
奔溃先找输入
题解
与上一个相似,但也做了些更改
#include <iostream>
#include <cmath>
#include <vector>
using namespace std;
int n, maxdepth = 0, maxnum = 0, temp, root;
vector<int> v[100010];
void dfs(int index, int depth) { ///深度搜索
if(v[index].size() == 0) {
if(maxdepth == depth)
maxnum++;
if(maxdepth < depth) {
maxdepth = depth;
maxnum = 1;
}
return ;
}
for(int i = 0; i < v[index].size(); i++)
dfs(v[index][i], depth + 1);
}
int main() {
double p, r;
scanf("%d %lf %lf", &n, &p, &r);
for(int i = 0; i < n; i++) {
scanf("%d", &temp);
if(temp == -1)
root = i;
else
v[temp].push_back(i);
}
dfs(root, 0);
printf("%.2f %d", p * pow(1 + r/100, maxdepth), maxnum);
return 0;
}