目录
- 1031 Hello World for U (20分) 推荐指数:1星
- 1032 Sharing (25分)
- 1033 To Fill or Not to Fill (25分)推荐:1星
- 1034 Head of a Gang (30分) 推荐:1星
- 1035 Password (20分)
- 1036 Boys vs Girls (25分)
- 1037 Magic Coupon (25分)
- 1038 Recover the Smallest Number (30分) 推荐:2星
- 1039 Course List for Student (25分)
- 1040 Longest Symmetric String (25分) 推荐:两星
1031 Hello World for U (20分) 推荐指数:1星
题目
Sample Input:
helloworld!
Sample Output:
h !
e d
l l
lowor
分析
推荐指数:1星。
按照指定形状输出数据,也是一个常考的知识点。像U形,回型等。
要点
- 延边遍历,需要固定住某一遍
- strlen(s) + 2其实是由题目得出的条件,(因为两个角有重复)
- 从后遍历,要检查 i–
- 使用memset来进行 0, 1, ’ '的赋值
题解
#include <iostream>
#include <string.h>
using namespace std;
int main(){
#ifndef ONLINE_JUDGE
freopen("data.txt", "r", stdin);
#endif // ONLINE_JUDGE
char c[81], u[30][30];
memset(u, ' ', sizeof(u)); ///另一种赋值形式
scanf("%s", c);
int n = strlen(c) + 2;
int n1 = n / 3, n2 = n / 3 + n % 3, index = 0; ///这个求出来题就解了
for(int i = 0; i < n1; i++) u[i][0] = c[index++];
for(int i = 1; i <= n2 - 2; i++) u[n1-1][i] = c[index++];
for(int i = n1 - 1; i >= 0; i--) u[i][n2-1] = c[index++];
for(int i = 0; i < n1; i++) {
for(int j = 0; j < n2; j++)
printf("%c", u[i][j]);
printf("\n");
}
return 0;
}
1032 Sharing (25分)
题目
Sample Input 1:
11111 22222 9
67890 i 00002
00010 a 12345
00003 g -1
12345 D 67890
00002 n 00003
22222 B 23456
11111 L 00001
23456 e 67890
00001 o 00010
Sample Output 1:
67890
Sample Input 2:
00001 00002 4
00001 a 10001
10001 s -1
00002 a 10002
10002 t -1
Sample Output 2:
-1
分析
静态数组的题目
要点
- 使用scanf的时候,在有%c时,必须每一位都对齐输入
- 使用结构体记录的情况下,可以将visit数组对应为struct中的flag属性
- 结构体的快速构建: node[a] = {data, b, false}
- 遍历 数组链表可以用for,也可以用while
题解
#include <cstdio>
using namespace std;
struct NODE {
char key;
int next;
bool flag; ///思考的一样,有个标志判断上一个是否visit过
}node[100000]; ///由题知N<=100000, 故直接使用链接数组即可
int main() {
int s1, s2, n, a, b;
scanf("%d%d%d", &s1, &s2, &n);
char data;
for(int i = 0; i < n; i++) {
scanf("%d %c %d", &a, &data, &b);
node[a] = {data, b, false}; ///结构体的快速赋值
}
for(int i = s1; i != -1; i = node[i].next)
node[i].flag = true;
for(int i = s2; i != -1; i = node[i].next) {
if(node[i].flag == true) {
printf("%05d", i);
return 0;
}
}
printf("-1");
return 0;
}
1033 To Fill or Not to Fill (25分)推荐:1星
题目
Sample Input 1:
50 1300 12 8
6.00 1250
7.00 600
7.00 150
7.10 0
7.20 200
7.50 400
7.30 1000
6.85 300
Sample Output 1:
749.17
Sample Input 2:
50 1300 12 2
7.10 0
7.00 600
Sample Output 2:
The maximum travel distance = 1200.00
分析
推荐:1星
这道题有3星的难度,模拟题,难度在于判断条件和思路。
需要尽量想好各种意外情况。
难点,在于条件判断较多,模拟思路很重要。
要点
- 起点、终点的处理。
- 过滤掉已经开过的点
- leftDis : 到站后,还有多少距离可以开,这个变量主要应对:可行驶距离内,没有比当前站更合算的价格,所以当前站要多买,后面看情况选一个
- 当最小点,且接下来极小点比不过最小点情况时,最小点加满,余下补上极点
题解
///只是穷举
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int inf = 99999999;
struct station {
double price, dis;
};
bool cmp1(station a, station b) { ///按距离排序
return a.dis < b.dis;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("data.txt", "r", stdin);
#endif // ONLINE_JUDGE
double cmax, d, davg;
int n;
scanf("%lf%lf%lf%d", &cmax, &d, &davg, &n);
vector<station> sta(n + 1);
sta[0] = {0.0, d}; ///终点站
for(int i = 1; i <= n; i++)
scanf("%lf%lf", &sta[i].price, &sta[i].dis);
sort(sta.begin(), sta.end(), cmp1);
double nowdis = 0.0, maxdis = 0.0, nowprice = 0.0, totalPrice = 0.0, leftdis = 0.0;
if(sta[0].dis != 0) { ///第一个油点就到不了——考虑开头, 中途, 结尾3段
printf("The maximum travel distance = 0.00");
return 0;
} else {
nowprice = sta[0].price; ///当前需要花费的油钱
}
while(nowdis < d) {
maxdis = nowdis + cmax * davg; ///当前能开的最远距离
double minPriceDis = 0, minPrice = inf; ///遍历所有可到达的点,找到最便宜的可到达点
int flag = 0;
for(int i = 1; i <= n && sta[i].dis <= maxdis; i++) { ///由近到远遍历
if(sta[i].dis <= nowdis) continue; ///已经开过的点
if(sta[i].price < nowprice) { ///可以去的点
totalPrice += (sta[i].dis - nowdis - leftdis) * nowprice / davg;
leftdis = 0.0;
nowprice = sta[i].price;
nowdis = sta[i].dis;
flag = 1;
break;
}
if(sta[i].price < minPrice) {
minPrice = sta[i].price;
minPriceDis = sta[i].dis;
}
}
if(flag == 0 && minPrice != inf) {
totalPrice += (nowprice * (cmax - leftdis / davg));
leftdis = cmax * davg - (minPriceDis - nowdis);
nowprice = minPrice;
nowdis = minPriceDis;
}
if(flag == 0 && minPrice == inf) { ///最后到不了的点
nowdis += cmax * davg;
printf("The maximum travel distance = %.2f", nowdis);
return 0;
}
}
printf("%.2f", totalPrice);
return 0;
}
1034 Head of a Gang (30分) 推荐:1星
题目
Sample Input 1:
8 59
AAA BBB 10
BBB AAA 20
AAA CCC 40
DDD EEE 5
EEE DDD 70
FFF GGG 30
GGG HHH 20
HHH FFF 10
Sample Output 1:
2
AAA 3
GGG 3
Sample Input 2:
8 70
AAA BBB 10
BBB AAA 20
AAA CCC 40
DDD EEE 5
EEE DDD 70
FFF GGG 30
GGG HHH 20
HHH FFF 10
Sample Output 2:
0
分析
推荐:经典
dfs经典题 : 可直接用作同类型的模板
要点
- 字符串 和 整型的映射
- travel中还有一个条件判断
- dfs中用别名来实现数值的累加
题解
#include <iostream>
#include <map>
using namespace std;
map<string, int> stringToInt;
map<int, string> intToString;
map<string, int> ans; ///人名《——》权重
int idNumber = 1, k;
int stoifunc(string s) { ///将字符串转换成数字,以便后面做图搜索
if(stringToInt[s] == 0) { ///如果没有
stringToInt[s] = idNumber;
intToString[idNumber] = s;
return idNumber++;
} else {
return stringToInt[s];
}
}
int G[2010][2010], weight[2010]; ///给的范围要根据题意来
bool vis[2010];
void dfs(int u, int &head, int &numMember, int &totalweight) { ///三个别名
vis[u] = true; ///已查
numMember++; ///人数++
if(weight[u] > weight[head]) ///边界条件的处理
head = u;
for(int v = 1; v < idNumber; v++) {
if(G[u][v] > 0) { ///有路可去
totalweight += G[u][v];
G[u][v] = G[v][u] = 0; ///置零-》防止回环
if(vis[v] == false) ///还未去过的点
dfs(v, head, numMember, totalweight);
}
}
}
void dfsTrave() {
for(int i = 1; i < idNumber; i++) {
if(vis[i] == false) { ///开始搜索
int head = i, numMember = 0, totalweight = 0;
dfs(i, head, numMember, totalweight);
if(numMember > 2 && totalweight > k) ///如果人数大于2且过阈值
ans[intToString[head]] = numMember;
}
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("data.txt", "r", stdin);
#endif // ONLINE_JUDGE
int n, w;
cin >> n >> k;
string s1, s2;
for(int i = 0; i < n; i++) {
cin >> s1 >> s2 >> w;
int id1 = stoifunc(s1);
int id2 = stoifunc(s2);
weight[id1] += w; ///每个点的总权重
weight[id2] += w;
G[id1][id2] += w; /// A->B + B->A == A-B
G[id2][id1] += w;
}
dfsTrave();
cout << ans.size() << endl;
for(auto it = ans.begin(); it != ans.end(); it++)
cout << it->first << " " << it->second << endl;
return 0;
}
1035 Password (20分)
题目
Sample Input 1:
3
Team000002 Rlsp0dfa
Team000003 perfectpwd
Team000001 R1spOdfa
Sample Output 1:
2
Team000002 RLsp%dfa
Team000001 R@spodfa
Sample Input 2:
1
team110 abcdefg332
Sample Output 2:
There is 1 account and no account is modified
Sample Input 3:
2
team110 abcdefg222
team220 abcdefg333
Sample Output 3:
There are 2 accounts and no account is modified
题解
//需要仔细审题
#include <string>
#include <iostream>
#include <vector>
using namespace std;
int main() {
#ifndef ONLINE_JUDGE
freopen("data.txt", "r", stdin);
#endif
int n;
scanf("%d", &n);
vector<string> v;
for (int i = 0; i < n; ++i) {
string name, password;
cin >> name >> password;
int len = password.size(), flag = 0;
for (int j = 0; j < len; ++j) {
switch (password[j]) {
case '1': password[j] = '@' ; flag = 1; break;
case '0': password[j] = '%'; flag = 1; break;
case 'l': password[j] = 'L'; flag = 1; break;
case 'O': password[j] = 'o'; flag = 1; break;
}
}
if (flag) {
string tmp = name + " " + password;
v.push_back(tmp);
}
}
int cnt = v.size();
if (cnt != 0) {
printf("%d\n", cnt);
for (int i = 0; i < cnt; ++i) {
cout << v[i] << endl;
}
}
else if (n == 1) {
printf("There is 1 account and no account is modified");
}
else {
printf("There are %d accounts and no account is modified", n); //这些应该直接从题干复制过来
}
return 0;
}
1036 Boys vs Girls (25分)
题目
Sample Input 1:
3
Joe M Math990112 89
Mike M CS991301 100
Mary F EE990830 95
Sample Output 1:
Mary EE990830
Joe Math990112
6
Sample Input 2:
1
Jean M AA980920 60
Sample Output 2:
Absent
Jean AA980920
NA
分析
寻找最值的题通常只需要一个变量来记录即可。
不同最值则设不同变量。
题解
///遍历数组,找最大最小值,并记录
#include <string>
#include <iostream>
using namespace std;
int main() {
#ifndef ONLINE_JUDGE
freopen("data.txt", "r", stdin);
#endif
int n;
scanf("%d", &n);
string female, male;
int femalescore = -1, malescore = 101;
for (int i = 0; i < n; ++i) {
string name, sex, id;
cin >> name >> sex >> id;
int score;
scanf("%d", &score);
if (sex == "F") {
if (femalescore < score) {
femalescore = score;
female = name + " " + id;
}
}
else {
if (malescore > score) {
malescore = score;
male = name + " " + id;
}
}
}
if (femalescore != -1) {
cout << female << endl;
}
else {
printf("Absent\n");
}
if (malescore != 101) {
cout << male << endl;
}
else {
printf("Absent\n");
}
if (femalescore != -1 && malescore != 101) {
printf("%d", femalescore - malescore);
}
else {
printf("NA");
}
return 0;
}
1037 Magic Coupon (25分)
题目
Sample Input:
4
1 2 4 -1
4
7 6 -2 -3
Sample Output:
43
分析
思路,把 最小负号的相乘 + 最大正数相乘 = 结果值
题解
#include <algorithm>
#include <iostream>
using namespace std;
long long a[100010], b[100010], sum = 0;
int main() {
int x, y;
scanf("%d", &x);
for (int i = 0; i<x; i++) scanf("%lld", &a[i]);
scanf("%d", &y);
for (int i = 0; i<y; i++) scanf("%lld", &b[i]);
sort(a, a + x); ///从小到达排序
sort(b, b + y);
int j = 0, k = 0;
while (a[j]<0 && b[k]<0) { //这里不用过多限定,因为输入本身就有一定的限定
sum += a[j] * b[k];
j++; k++;
}
j = x - 1; k = y - 1;
while (a[j]>0 && b[k]>0) {
sum += a[j] * b[k];
j--; k--;
}
printf("%lld", sum);
return 0;
}
1038 Recover the Smallest Number (30分) 推荐:2星
题目
Sample Input:
5 32 321 3214 0229 87
Sample Output:
22932132143287
分析
推荐:2星
没思路的话,也可以直接穷举,至少能得一些分。
要点
- 直接拼接字符串 a 和 b 即可
题解
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
bool cmp0(string a, string b) {
return a + b < b + a; ///比较两个的拼接, 既然两个不等,拼接上就可以啦
}
string str[10010];
int main() {
#ifndef ONLINE_JUDGE
freopen("data.txt", "r", stdin);
#endif // ONLINE_JUDGE
int n;
scanf("%d", &n);
for(int i = 0; i < n; i++)
cin >> str[i];
sort(str, str + n, cmp0);
string s;
for(int i = 0; i < n; i++) ///结果拼凑
s += str[i];
while(s.length() != 0 && s[0] == '0') ///过滤队首的0
s.erase(s.begin());
if(s.length() == 0) cout << 0; ///特判
cout << s;
return 0;
}
1039 Course List for Student (25分)
题目
Sample Input:
11 5
4 7
BOB5 DON2 FRA8 JAY9 KAT3 LOR6 ZOE1
1 4
ANN0 BOB5 JAY9 LOR6
2 7
ANN0 BOB5 FRA8 JAY9 JOE4 KAT3 LOR6
3 1
BOB5
5 9
AMY7 ANN0 BOB5 DON2 FRA8 JAY9 KAT3 LOR6 ZOE1
ZOE1 ANN0 BOB5 JOE4 JAY9 FRA8 DON2 AMY7 KAT3 LOR6 NON9
Sample Output:
ZOE1 2 4 5
ANN0 3 1 2 5
BOB5 5 1 2 3 4 5
JOE4 1 2
JAY9 4 1 2 4 5
FRA8 3 2 4 5
DON2 2 4 5
AMY7 1 5
KAT3 3 2 4 5
LOR6 4 1 2 4 5
NON9 0
分析
使用散列可以大大提高查询的速度,但更占内存, getID是关键,只适用于3~5个字符
使用map和set可以更加快速的实现。其实也差不多啦
各有优劣,视情况使用
题解
本题用的散列,查表,我的话可能会用map来记录每个学生
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
int getid(char *name) { ///散列,学生名称由4个字符构成
int id = 0;
for(int i = 0; i < 3; i++) ///3个Letter
id = 26 * id + (name[i] - 'A');
id = id * 10 + (name[3] - '0'); ///1个数字
return id;
}
const int maxn = 26 * 26 * 26 * 10 + 10; ///最大
vector<int> v[maxn]; ///直接开向量数组
int main() {
#ifndef ONLINE_JUDGE
freopen("data.txt", "r", stdin);
#endif // ONLINE_JUDGE
int n, k, no, num, id = 0;
char name[5];
scanf("%d %d", &n, &k);
for(int i = 0; i < k; i++) {
scanf("%d %d", &no, &num);
for(int j = 0; j < num; j++) {
scanf("%s", name);
id = getid(name);
v[id].push_back(no);
}
}
for(int i = 0; i < n; i++) {
scanf("%s", name);
id = getid(name);
sort(v[id].begin(), v[id].end());
printf("%s %lu", name, v[id].size()); /// .size()返回unsighed int, 用d也可以,不行就用lu
for(int j = 0; j < v[id].size(); j++)
printf(" %d", v[id][j]);
printf("\n");
}
return 0;
}
1040 Longest Symmetric String (25分) 推荐:两星
题目
Sample Input:
Is PAT&TAP symmetric?
Sample Output:
11
分析
推荐:两星
最长回文字符串:
1.动态规划 :dp数组是关键,理解成每一个维都一个字符串, 然后是匹配长度
dp[i][j]的意思, 从i到j都相等
2.马拉车算法(化奇偶为奇)
要点:插入#,开头入$, 求p数组, 从左往右,j点作为曾经的点已经算过
j = 2*id - i , j 是 i 关于id的对称点
3.暴力解法(中间扩展):可以用来获取一部分分数,可以全对,判断奇偶关系即可
4.扩张KMP算法
注意:出错第一遍,先检查ONLINE_JUDGE
要点
动态规划:字符串匹配的关键在于如何利用已经计算过得部分
题解
动态规划
#include <iostream>
using namespace std;
int dp[1010][1010];
int main() {
#ifndef ONLINE_JUDGE
freopen("data.txt", "r", stdin);
#endif // ONLINE_JUDGE
string s;
getline(cin, s);
int len = s.length(), ans = 1;
///i与i,i与i-1相比较, 所有长度为2的相同已匹配完
for(int i = 0; i < len; i++) { ///找到前后一样的字母
dp[i][i] = 1;
///解决偶数的数据
if(i < len - 1 && s[i] == s[i+1]) {
dp[i][i+1] = 1;
ans = 2;
}
}
///算法复杂度近似 nlogn
///L==3 , i = 0时, j = 2, i+1 = 1 , j - 1 = 1, 即中心位置
for(int L = 3; L <= len; L++) { ///从3开始找, 状态转移方程
for(int i = 0; i + L - 1 < len; i++) {
int j = i + L -1;
///L==3 , i = 0时, j = 2, i+1 = 1 , j - 1 = 1, 即中心位置,状态转移
if(s[i] == s[j] && dp[i+1][j-1] == 1) {
dp[i][j] = 1;
ans = L;
}
}
}
printf("%d", ans);
return 0;
}
暴力解法
#include <iostream>
using namespace std;
int main(){
#ifndef ONLINE_JUDGE
freopen("data.txt", "r", stdin);
#endif // ONLINE_JUDGE
string s;
int maxLength = 0;
getline(cin, s);
for(int i = 0; i < s.length(); i++){
int j = 1;
while(i - j > 0 && i+j < s.length() && s[i-j] == s[j+i])
j++;
if (maxLength < j*2-1)
maxLength = j * 2 -1;
j = i+1;
int t = i;
while(t>=0 && j<s.length() && s[t] == s[j]){
t--;j++;
}
if (maxLength < j-t-1)
maxLength = j-t-1;
}
printf("%d", maxLength);
}