前言
记录PAT刷题笔记和代码。算法笔记中例题的记录已经放在《算法刷题笔记》文章中了。以下是PAT题库中算法笔记中未出现的题目,这里均为PAT甲级题目。涉及树、图、并查集、堆的题目单独分类了,不在此目录中。
目录
A1069 The Black Hole of Numbers
A1124 Raffle for Weibo Followers
A1141 PAT Ranking of Institutions
A1145 Hashing - Average Search Time
A1148 Werewolf - Simple Version
A1149 Dangerous Goods Packaging
A1153 Decode Registration Card of PAT
甲级
-
A1061 Dating
字符串扫描匹配。注意字符范围要在合理的范围内,否则会出错,比如对于第一个相同的大写字母,表示星期几,需要在'A'~'G'之间。
#include<cstdio>
#include<iostream>
#include<string>
#include<cctype>
using namespace std;
string date[7] = {"MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"};
int main() {
string s1, s2, s3, s4;
cin >> s1 >> s2 >> s3 >> s4;
int cnt = 0;
for(int i = 0; i < s1.length() || i < s2.length(); i ++) {
if(cnt == 1 && s1[i] == s2[i] && (isdigit(s1[i]) || s1[i] >= 'A' && s1[i] <= 'N')) {
if(isdigit(s1[i]))
printf(" %02d:", s1[i] - '0');
else
printf(" %02d:", s1[i] - 'A' + 10);
break;
}
if(s1[i] == s2[i] && s1[i] >= 'A' && s1[i] <= 'G') {
if(cnt == 0)
printf("%s", date[s1[i] - 'A'].c_str());
cnt = 1;
}
}
for(int i = 0; i < s3.length() || i < s4.length(); i ++) {
if(s3[i] == s4[i] && isalpha(s3[i])) {
printf("%02d", i);
break;
}
}
return 0;
}
-
A1062 Talent and Virtue
关键是定义结构体和排序函数。结构体变量中包含id,virtue,talent,还包括一个VT,0表示not rank, 1表示foolman(v>=t),2表示nobleman(Vt),3表示sage(VT)。不满足virtue和talent均不小于L的直接不读入。
排序规则如下:
bool cmp(Man a, Man b) {
if(a.VT != b.VT)
return a.VT > b.VT;
else if(a.virtue + a.talent != b.virtue + b.talent)
return a.virtue + a.talent > b.virtue + b.talent;
else if(a.virtue != b.virtue)
return a.virtue > b.virtue;
else
return a.id < b.id;
}
AC代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 100010;
struct Man {
int id, virtue, talent;
int VT; // 0:not rank 1 : v>=h (foolman) 2: Vt(nobleman) 3: VT(sage)
}man[maxn];
bool cmp(Man a, Man b) {
if(a.VT != b.VT)
return a.VT > b.VT;
else if(a.virtue + a.talent != b.virtue + b.talent)
return a.virtue + a.talent > b.virtue + b.talent;
else if(a.virtue != b.virtue)
return a.virtue > b.virtue;
else
return a.id < b.id;
}
int main() {
int N, L, H, id, v, t;
scanf("%d %d %d", &N, &L, &H);
int cnt = 0;
for(int i = 0; i < N; i ++) {
scanf("%d %d %d", &id, &v, &t);
if(v >= L && t >= L) {
man[cnt].id = id;
man[cnt].virtue = v;
man[cnt].talent = t;
if(v >= H && t >= H) {
man[cnt].VT = 3;
}
else if(v >= H && t < H) {
man[cnt].VT = 2;
}
else if(v < H && t < H && v >= t) {
man[cnt].VT = 1;
}
else man[cnt].VT = 0;
cnt ++;
}
}
sort(man, man + cnt, cmp);
printf("%d\n", cnt);
for(int i = 0; i < cnt; i ++) {
printf("%08d %d %d\n", man[i].id, man[i].virtue, man[i].talent);
}
return 0;
}
-
A1069 The Black Hole of Numbers
用string存放数字。注意输入的数字可能不到4位,需要补充前导0。然后对数字串sort排序,再reverse得到他的倒序,用stoi()转为数字求差,在to_string()转为string,补充前导0至4位,输出等式,然后将差的结果res赋值给num进行下一轮的模拟。
#include<cstdio>
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
int main() {
string num, num2, res = "";
cin >> num;
if(num[0] == num[1] && num[1] == num[2] && num[2] == num[3]) {
printf("%s - %s = 0000", num.c_str(), num.c_str());
return 0;
}
while(num.length() < 4)
num.insert(0, "0");
while(res != "6174") {
sort(num.begin(), num.end());
num2 = num;
reverse(num.begin(), num.end()); //larger
res = to_string(stoi(num) - stoi(num2));
while(res.length() < 4)
res.insert(0, "0");
printf("%s - %s = %s\n", num.c_str(), num2.c_str(), res.c_str());
num = res;
}
return 0;
}
-
A1070 Mooncake
贪心。按单价排序。
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 1010;
struct Mooncake {
double amount;
double totalMoney;
double price;
} mooncake[maxn];
bool cmp(Mooncake a, Mooncake b) {
return a.price > b.price;
}
int main() {
int N;
double D;
scanf("%d %lf", &N, &D);
for(int i = 0; i < N; i ++)
scanf("%lf", &mooncake[i].amount);
for(int i = 0; i < N; i ++)
scanf("%lf", &mooncake[i].totalMoney);
for(int i = 0; i < N; i ++)
mooncake[i].price = mooncake[i].totalMoney / mooncake[i].amount;
sort(mooncake, mooncake + N, cmp);
double sum = 0.0, totalAmount = 0;
for(int i = 0; i < N; i ++) {
if(totalAmount + mooncake[i].amount <= D) {
totalAmount += mooncake[i].amount;
sum += mooncake[i].totalMoney;
}
else {
sum += (D - totalAmount) * mooncake[i].price;
break;
}
}
printf("%.2f", sum);
return 0;
}
-
A1073 Scientific Notation
这题之前做过一般,这次还不是很熟练,最后好在是一遍过。大体思路有,但细节处理害怕没有考虑全。
思路:首先处理第一个正负号,是负号输出一个‘-’,否则不输出。然后把字符串第一个符号删去。
接下来获取指数E的位置,用substr获得底数部分n和指数部分e,根据指数部分的正负号将情况分为>1和<1两种情况。
小于1需先输出0.,然后不够e的补前导0。
大于1的情况回去指数部分大小,然后从移动小数点的方向考虑,当移动小数点不超过数字长度,则把小数点插到对应位置;否则需要补后面的0,不需要输出小数点。
#include<cstdio>
#include<iostream>
#include<string>
using namespace std;
int main() {
string num, n, e;
cin >> num;
if(num[0] == '-') printf("-");
num.erase(0, 1);
int pos = num.find('E');
n = num.substr(0, pos);
e = num.substr(pos + 1);
if(e[0] == '-') {
printf("0.");
n.erase(n.find('.'), 1);
int k = stoi(e.substr(1));
int i = 0;
while(i ++ < k - 1)
n.insert(0, "0");
printf("%s", n.c_str());
}
else {
int k = stoi(e.substr(1));
if(k < n.length() - 2) {
n.erase(n.find('.'), 1);
n.insert(k + 1, ".");
printf("%s", n.c_str());
}
else {
n.erase(n.find('.'), 1);
while(n.length() < k + 1)
n += "0";
printf("%s", n.c_str());
}
}
return 0;
}
-
A1074 Reversing Linked List
二刷,这次用的方法思路比第一次更直观,就是先获得一个链表的顺序数组,然后遍历链表将顺序数组中的顺序赋值为order,用于排序。
在实现上述过程中,需要注意一点的是,获得顺序数组时需要先遍历一遍数组获得有效节点个数N(而不是读入时的N,最后一个样例存在无效节点)。
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 100010;
struct Node {
int addr, data, next;
int order;
} node[maxn];
int order[maxn];
bool cmp(Node a, Node b) {
return a.order < b.order;
}
int main() {
for(int i = 0; i < maxn; i ++) {
node[i].order = maxn;
}
int start, N, K, id;
scanf("%d %d %d", &start, &N, &K);
for(int i = 0; i < N; i ++) {
scanf("%d", &id);
node[id].addr = id;
scanf("%d %d", &node[id].data, &node[id].next);
}
int p = start;
N = 0;
while(p != -1) {
N ++;
p = node[p].next;
} //先统计有效节点数
p = start;
int cnt = 0, n = N / K; //获得顺序数组
for(int i = 0; i < n; i ++) {
for(int j = (i + 1) * K - 1; j >= i * K; j --) {
order[j] = cnt ++;
}
}
for(int i = n * K; i < N; i ++)
order[i] = cnt ++;
cnt = 0;
while(p != -1) { //设置顺序
node[p].order = order[cnt ++];
p = node[p].next;
}
sort(node, node + maxn, cmp);
for(int i = 0; i < cnt; i ++) {
printf("%05d %d", node[i].addr, node[i].data);
if(i < cnt - 1) printf(" %05d\n", node[i + 1].addr);
else printf(" -1\n");
}
return 0;
}
-
A1084 Broken Keyboard
hash表的思想。遍历字符串1,将出现的字符(字母大写)的hash值置为1,遍历字符串2,将出现的字符(字母大写)的hash值置0。再次遍历字符串1,按输入顺序判断对应字符hash值是否为1,为1表示没有成功打出,则输出并将hash值置0,遍历置字符串结尾。
#include<cstdio>
#include<iostream>
#include<string>
#include<cctype>
using namespace std;
int hashTable[300] = {0};
int main() {
string s1, s2;
cin >> s1 >> s2;
for(int i = 0; i < s1.length(); i ++)
hashTable[toupper(s1[i])] = 1;
for(int i = 0; i < s2.length(); i ++)
hashTable[toupper(s2[i])] = 0;
for(int i = 0; i < s1.length(); i ++) {
if(hashTable[toupper(s1[i])] == 1) {
printf("%c", toupper(s1[i]));
hashTable[toupper(s1[i])] = 0;
}
}
return 0;
}
-
A1088 Rational Arithmetic
分数四则运算。有模板。注意点:分子分母和gcd一般需要用long long存储,因为常常成绩会超过int范围。
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL;
struct Fraction {
LL up, down;
};
LL gcd(LL a, LL b) {
if(b == 0) return a;
else return gcd(b, a % b);
}
//化简
Fraction reduction(Fraction res) {
if(res.down < 0) {
res.up = -res.up;
res.down = -res.down;
}
if(res.up == 0) {
res.down = 1;
}
else {
int d = gcd(abs(res.up), abs(res.down));
res.up /= d;
res.down /= d;
}
return res;
}
Fraction add(Fraction a, Fraction b) {
Fraction res;
res.up = a.up * b.down + b.up * a.down;
res.down = a.down * b.down;
return reduction(res);
}
Fraction sub(Fraction a, Fraction b) {
Fraction res;
res.up = a.up * b.down - b.up * a.down;
res.down = a.down * b.down;
return reduction(res);
}
Fraction multi(Fraction a, Fraction b) {
Fraction res;
res.up = a.up * b.up;
res.down = a.down * b.down;
return reduction(res);
}
Fraction divide(Fraction a, Fraction b) {
Fraction res;
res.up = a.up * b.down;
res.down = a.down * b.up;
return reduction(res);
}
void print(Fraction a) {
a = reduction(a);
if(a.down == 1) printf("%lld", a.up); //整数
else if(abs(a.up) > a.down) { //假分数
printf("%d %d/%d", a.up / a.down, abs(a.up) % a.down, a.down);
}
else {
printf("%d/%d", a.up, a.down);
}
}
int main() {
Fraction a, b, c;
scanf("%lld/%lld %lld/%lld", &a.up, &a.down, &b.up, &b.down);
char op[4] = {'+', '-', '*', '/'};
for(int i = 0; i < 4; i ++) {
if(a.up < 0) printf("(");
print(a);
if(a.up < 0) printf(")");
printf(" %c ", op[i]);
if(b.up < 0) printf("(");
print(b);
if(b.up < 0) printf(")");
printf(" = ");
switch(i) {
case 0: c = add(a, b); break;
case 1: c = sub(a, b); break;
case 2: c = multi(a, b); break;
case 3:
if(b.up != 0)
c = divide(a, b); break;
}
if(i == 3 && b.up == 0) {
printf("Inf");
}
else {
if(c.up < 0) printf("(");
print(c);
if(c.up < 0) printf(")");
}
printf("\n");
}
}
-
A1089 Insertion or Merge
二刷,注意下标是从1开始还是从0开始。每一轮排序前判断当前序列和目标序列是否相同。
其中插入排序的部分的解释:循环遍历i表示排序的轮数。
每一轮(i)排好前i + 1个(i == 1时,排0 ~ 2)。(当i从1开始(数组下标从0开始)时,就是sort(a, a + i + 1); 当i从2开始(数组下标从1开始)时是sort(a + 1, a + i + 1))。
归并排序:用不断*2的step(step从2开始,表示每个块内的元素个数)遍历数组,每一轮排好每个块内的子数组。
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 110;
int origin[maxn], tempOri[maxn], changed[maxn];
int N;
bool isSame(int a[], int b[]) {
for(int i = 0; i < N; i ++)
if(a[i] != b[i])
return false;
return true;
}
void printArray(int a[]) {
for(int i = 0; i < N; i ++) {
if(i > 0) printf(" ");
printf("%d", a[i]);
}
}
bool insertionSort() {
bool flag = false;
for(int i = 1; i < N; i ++) { //进行N - 1次排序(这里的i和数组下标无关)
if(i != 1 && isSame(tempOri, changed)) flag = true;
sort(tempOri, tempOri + i + 1); //这里的范围是0~(i+1),i = 1: 排0-2
// int temp = tempOri[i], j = i;
// while(j > 0 && tempOri[j - 1] > temp) {
// tempOri[j] = tempOri[j - 1];
// j --;
// }
// tempOri[j] = temp;
if(flag == true) return true;
}
return false;
}
void mergeSort() {
bool flag = false;
for(int step = 2; step / 2 <= N; step *= 2) {
if(step != 2 && isSame(tempOri, changed)) {
flag = true;
}
for(int i = 0; i < N; i += step) {
sort(tempOri + i, tempOri + min(i + step , N));
}
if(flag == true) {
printArray(tempOri);
return;
}
}
}
int main() {
scanf("%d", &N);
for(int i = 0; i < N; i ++) {
scanf("%d", &origin[i]);
tempOri[i] = origin[i];
}
for(int i = 0; i < N; i ++) {
scanf("%d", &changed[i]);
}
if(insertionSort()) {
printf("Insertion Sort\n");
printArray(tempOri);
}
else {
printf("Merge Sort\n");
for(int i = 0; i < N; i ++)
tempOri[i] = origin[i];
mergeSort();
}
return 0;
}
-
A1092 To Buy or Not to Buy
二刷。hash。
#include<cstdio>
#include<iostream>
#include<string>
using namespace std;
int hashTable[300] = {0};
int main() {
string a, b;
cin >> a >> b;
for(int i = 0; i < a.length(); i ++) {
hashTable[a[i]] ++;
}
int cnt = 0;
for(int i = 0; i < b.length(); i ++) {
if(hashTable[b[i]] > 0) {
hashTable[b[i]] --;
}
else {
cnt ++;
}
}
if(cnt > 0) printf("No %d", cnt);
else printf("Yes %d", a.length() - b.length());
return 0;
}
-
A1093 Count PAT's
二刷,但第一眼还是没思路。
思路:对于每一个A,统计左边的P的个数和右边的T的个数。PAT的个数等于左边的P的个数乘以右边的T的个数。关键再用如何统计:从左到右遍历字符串,左边的P的个数至少等于前一项,当s[i] == 'P'时,加1。同理右边的T的个数从右到左遍历,同时遇到'A'将结果加到ans。
#include<cstdio>
#include<iostream>
#include<string>
using namespace std;
const int maxn = 100010;
const int MOD = 1000000007;
int leftNumP[maxn] = {0};
int main() {
string s;
cin >> s;
for(int i = 0; i < s.length(); i ++) {
if(i > 0)
leftNumP[i] = leftNumP[i - 1];
if(s[i] == 'P')
leftNumP[i] ++;
}
int ans = 0, rightNumT = 0;
for(int i = s.length() - 1; i >= 0; i --) {
if(s[i] == 'T')
rightNumT ++;
else if(s[i] == 'A')
ans = (ans + leftNumP[i] * rightNumT) % MOD;
}
printf("%d", ans);
return 0;
}
-
A1100 Mars Numbers
二刷,不熟。设置两个映射num2str和str2num。
坑点:str2num时读入需要用getline,因为读入一行含空格的字符串。
打表的方法:先将1~13填好(unitDigit),及13的倍数填好(tenDigit)。再按照先十位(i)后个位(j)的方法遍历填充。s = tenDigit[i] + " " + unitDigit[j]。
#include<cstdio>
#include<iostream>
#include<string>
#include<map>
#include<cctype>
using namespace std;
string unitDigit[13] = {
"tret",
"jan", "feb", "mar", "apr", "may", "jun",
"jly", "aug", "sep", "oct", "nov", "dec"
};
string tenDigit[13] = {
"tret",
"tam", "hel", "maa", "huh", "tou", "kes",
"hei", "elo", "syy", "lok", "mer", "jou",
};
map<int, string> num2str;
map<string, int> str2num;
void init() {
for(int i = 0; i < 13; i ++) {
num2str[i] = unitDigit[i];
str2num[unitDigit[i]] = i;
num2str[i * 13] = tenDigit[i];
str2num[tenDigit[i]] = i * 13;
}
for(int i = 1; i < 13; i ++) {
for(int j = 1; j < 13; j ++) {
string s = tenDigit[i] + " " + unitDigit[j];
num2str[i * 13 + j] = s;
str2num[s] = i * 13 + j;
}
}
}
int main() {
init();
int n;
string s;
cin >> n;
getchar();
for(int i = 0; i < n; i ++) {
getline(cin, s);
if(isdigit(s[0])) {
cout << num2str[stoi(s)] << endl;
}
else
cout << str2num[s] << endl;
}
return 0;
}
-
A1101 Quick Sort
题意:判断元素是否可能是快排中的主元。只需判断元素是否比左边最大的大,比右边最小的小。因此对于每个元素i需要统计leftMax[i]和rightMin[i]。注意左边最大值和右边最小值的计算过程中不包括元素本身。
坑点:最后需要一个换行。
#include<cstdio>
const int maxn = 100010;
int a[maxn], ans[maxn];
int leftMax[maxn], rightMin[maxn];
int main() {
int n;
scanf("%d", &n);
for(int i = 0; i < n; i ++) {
scanf("%d", &a[i]);
}
leftMax[0] = 0;
for(int i = 1; i < n; i ++) {
if(a[i - 1] > leftMax[i - 1]) {
leftMax[i] = a[i - 1];
}
else
leftMax[i] = leftMax[i - 1];
}
rightMin[n - 1] = 1000000001;
for(int i = n - 2; i >= 0; i --) {
if(a[i + 1] < rightMin[i + 1]) {
rightMin[i] = a[i + 1];
}
else
rightMin[i] = rightMin[i + 1];
}
int cnt = 0;
for(int i = 0; i < n; i ++) {
if(a[i] > leftMax[i] && a[i] < rightMin[i]) {
ans[cnt ++] = a[i];
}
}
printf("%d\n", cnt);
for(int i = 0; i < cnt; i ++) {
if(i > 0) printf(" ");
printf("%d", ans[i]);
}
printf("\n");
return 0;
}
-
A1104 Sum of Number Segments
找数学规律。数组系数为i * (n - i + 1)。
坑点:数据范围,需要用long double存储。
#include<cstdio>
int main() {
int n;
scanf("%d", &n);
long double a, sum = 0.0;
for(int i = 1; i <= n; i ++) {
scanf("%llf", &a);
sum += a * i * (n - i + 1);
}
printf("%.2llf\n", sum);
return 0;
}
-
A1105 Spiral Matrix
重点:获得N的最相近的两个因子的方法:先取m = (int) ceil(sqrt(1.0 * N)),然后遍历至N% m即可。n = N / m。
坑点:当N == 1时,需特判输出。
思路:将数组排好序。用L, R,U, D四个边界遍历矩阵,每次边界内缩,i ++,j++跳到内一层。第N-1个数特殊处理。
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn = 10010;
int a[maxn];
int matrix[maxn][maxn];
bool cmp(int a, int b) {
return a > b;
}
int main() {
int N;
scanf("%d", &N);
for(int i = 0; i < N; i ++)
scanf("%d", &a[i]);
if(N == 1) {
printf("%d", a[0]);
return 0;
}
sort(a, a + N, cmp);
int m = (int)ceil(sqrt(1.0 * N));
while(N % m != 0)
m ++;
int n = N / m;
int L = 1, R = n, U = 1, D = m;
int i = 1, j = 1, num = 0;
while(num < N) {
while(num < N && j < R) {
matrix[i][j] = a[num ++];
j ++;
}
while(num < N && i < D) {
matrix[i][j] = a[num ++];
i ++;
}
while(num < N && j > L) {
matrix[i][j] = a[num ++];
j --;
}
while(num < N && i > U) {
matrix[i][j] = a[num ++];
i --;
}
U ++, D --, L ++, R --;
i ++, j ++;
if(num == N - 1) {
matrix[i][j] = a[num ++];
}
}
for(int i = 1; i <= m; i ++) {
for(int j = 1; j <= n; j ++) {
printf("%d", matrix[i][j]);
if(j < n) printf(" ");
else printf("\n");
}
}
return 0;
}
-
A1108 Finding Average
二刷。发现样例没有两个负号的错误情况。基本上按描述写就能过。
#include<cstdio>
#include<iostream>
#include<string>
#include<cctype>
using namespace std;
bool isLegal(string s) {
for(int i = 0; i < s.length(); i ++) {
if(isalpha(s[i])) return false;
if(s[i] == '.') {
string ss = s.substr(s.find('.') + 1);
if(ss.length() > 2) return false;
if(ss.find('.') != string::npos) return false;
}
}
double d = stod(s);
if(d < -1000 || d > 1000) return false;
return true;
}
int main() {
int n;
scanf("%d", &n);
string s;
double sum = 0.0;
int cnt = 0;
for(int i = 0; i < n; i ++) {
cin >> s;
if(isLegal(s)) {
sum += stod(s);
cnt ++;
}
else {
printf("ERROR: %s is not a legal number\n", s.c_str());
}
}
if(cnt == 0) printf("The average of 0 numbers is Undefined\n");
else if(cnt == 1) printf("The average of 1 number is %.2f", sum);
else printf("The average of %d numbers is %.2f", cnt, sum / cnt);
return 0;
}
-
A1109 Group Photo
二刷。没有第一次顺滑。注意K为行数,不是每行人数。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<deque>
using namespace std;
const int maxn = 10010;
struct Student {
char name[9];
int height;
} stu[maxn];
bool cmp(Student a, Student b) {
if(a.height != b.height)
return a.height > b.height;
else
return strcmp(a.name, b.name) < 0;
}
int main() {
int N, K;
scanf("%d %d", &N, &K);
for(int i = 0; i < N; i ++) {
scanf("%s %d", stu[i].name, &stu[i].height);
}
sort(stu, stu + N, cmp);
deque<Student> q;
int rows = N / K;
int n = N - (K - 1) * rows;
int num, idx = 0;
for(int r = 0; r < K; r ++) {
if(r == 0) num = n;
else num = rows;
int cnt = 0;
while(1) {
q.push_back(stu[idx ++]);
if(++ cnt >= num) break;
q.push_front(stu[idx ++]);
if(++ cnt >= num) break;
}
for(int i = 0; i < q.size(); i ++) {
printf("%s", q[i].name);
if(i < q.size() - 1) printf(" ");
else printf("\n");
}
q.clear();
}
return 0;
}
-
A1110 Complete Binary Tree
完全没思路。。憋了半天还是看了题解。
思路:完全二叉树满足:最大下标值 == 最大节点数。递归得到最大下标值。若大于节点数则不是完全二叉树。
-
A1112 Stucked Keyboard
bug找了半天发现是加了个常量(快速debug能力很重要啊。)
思路:遍历字符串,统计连续相同字符个数,如果连续字符数不是k的倍数,则一定不可能是坏的,将hashTable[s[i]](原先初始化为1)置为0。
统计连续相同字符个数的方法:for(j = i; j < s.length() && s[j] == s[i]; j ++); 下一次循环i = j。
注意按照字符发现的顺序输出,不能直接按哈希表中的顺序输出。
输出原串时,第一次遇到坏字符时,将下标i直接后移(k - 1)个(一开始写成样例的的3 - 1了
(╥╯^╰╥))。
#include<cstdio>
#include<iostream>
#include<string>
using namespace std;
int hashTable[256] = {0};
int count[256] = {0};
int main() {
int k;
cin >> k;
string s;
cin >> s;
for(int i = 0; i < s.length(); i ++)
hashTable[s[i]] = 1;
int j;
for(int i = 0; i < s.length(); i = j) {
for(j = i; j < s.length() && s[j] == s[i]; j ++);
if((j - i) % k != 0) hashTable[s[i]] = 0;
}
for(int i = 0; i < s.length(); i ++) {
if(hashTable[s[i]] == 1 && count[s[i]] == 0) {
printf("%c", s[i]);
count[s[i]] = 1;
}
}
printf("\n");
for(int i = 0; i < s.length(); i ++) {
if(hashTable[s[i]] == 1) i += k - 1;
printf("%c", s[i]);
}
return 0;
}
-
A1113 Integer Set Partition
将整数分为两个集合,要求集合内整数个数差最小,集合内的整数和之差最大。
如果n是奇数,个数差最小为1,n为偶数则为0。和之差最大只需将数组排序,n / 2 给小数组,后 n / 2给大数组即可。
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 100010;
int a[maxn];
int main() {
int n, sum = 0;
scanf("%d", &n);
for(int i = 0; i < n; i ++) {
scanf("%d", &a[i]);
sum += a[i];
}
sort(a, a + n);
int s1 = 0;
for(int i = 0; i < n / 2; i ++) {
s1 += a[i];
}
printf("%d %d", n % 2, sum - s1 - s1);
return 0;
}
-
A1116 Come on! Let's C
水题:用map记录排名和查询情况,写个判断质数的函数就好了。
#include<cstdio>
#include<map>
using namespace std;
map<int, int> Rank, checked;
bool isPrime(int x) {
if(x < 2) return false;
for(int i = 2; i * i <= x; i ++)
if(x % i == 0)
return false;
return true;
}
int main() {
int n, k, id;
scanf("%d", &n);
for(int i = 1; i <= n; i ++) {
scanf("%d", &id);
Rank[id] = i;
}
scanf("%d", &k);
for(int i = 0; i < k; i ++) {
scanf("%d", &id);
if(Rank[id] == 0) {
printf("%04d: Are you kidding?\n", id);
}
else if(checked[id] != 0) {
printf("%04d: Checked\n", id);
}
else {
checked[id] = 1;
if(Rank[id] == 1) {
printf("%04d: Mystery Award\n", id);
}
else if(isPrime(Rank[id])) {
printf("%04d: Minion\n", id);
}
else {
printf("%04d: Chocolate\n", id);
}
}
}
return 0;
}
-
A1117 Eddington Number
二刷。从大到小sort,a[i] <= i时break。
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 100010;
int a[maxn];
bool cmp(int a, int b) {
return a > b;
}
int main() {
int n;
scanf("%d", &n);
for(int i = 1; i <= n; i ++)
scanf("%d", &a[i]);
sort(a + 1, a + n + 1, cmp);
int i;
for(i = 1; i <= n; i ++) {
if(a[i] <= i) break;
}
printf("%d", i - 1);
return 0;
}
-
A1120 Friend Numbers
#include<cstdio>
#include<iostream>
#include<string>
using namespace std;
int hashTable[40] = {0};
int main() {
int n;
scanf("%d", &n);
string num;
for(int i = 0; i < n; i ++) {
cin >> num;
int sum = 0;
for(int j = 0; j < num.size(); j ++)
sum += num[j] - '0';
hashTable[sum] = 1;
}
int cnt = 0;
int friendNum[40];
for(int i = 0; i < 40; i ++) {
if(hashTable[i] != 0) {
friendNum[cnt ++] = i;
}
}
printf("%d\n", cnt);
for(int i = 0; i < cnt; i ++) {
if(i > 0) printf(" ");
printf("%d", friendNum[i]);
}
return 0;
}
-
A1121 Damn Single
注:在原集合中查找删除的方法出现了段错误,使用新集合加入单身狗则可以通过。
#include<cstdio>
#include<map>
#include<set>
using namespace std;
map<int, int> couple;
int main() {
int n, m;
scanf("%d", &n);
int u, v;
for(int i = 0; i < n; i ++) {
scanf("%d %d", &u, &v);
couple[u] = v;
couple[v] = u;
}
scanf("%d", &m);
set<int> party, single;
for(int i = 0; i < m; i ++) {
scanf("%d", &u);
party.insert(u);
}
for(auto it : party) {
if(party.find(couple[it]) == party.end()) {
single.insert(it);
}
}
printf("%d\n", single.size());
for(auto it = single.begin(); it != single.end(); it ++) {
if(it != single.begin()) printf(" ");
printf("%05d", *it);
}
return 0;
}
-
A1124 Raffle for Weibo Followers
两个点:1、下标从1到m(<=m)2、while() i ++,而不是if() i ++,因为i ++下一个可能还是重复的。
#include<cstdio>
#include<iostream>
#include<string>
#include<map>
using namespace std;
const int maxn = 1010;
string namelist[maxn];
map<string, int> mp;
int main() {
int m, n, s;
scanf("%d %d %d", &m, &n, &s);
for(int i = 1; i <= m; i ++) {
cin >> namelist[i];
}
if(s > m) printf("Keep going...\n");
for(int i = s; i <= m; i += n) {
while(mp[namelist[i]] == 1) i ++;
printf("%s\n", namelist[i].c_str());
mp[namelist[i]] = 1;
}
return 0;
}
-
A1125 Chain the Ropes
优先队列(最小堆)。
#include<cstdio>
#include<queue>
using namespace std;
int main() {
int n, s;
priority_queue<int, vector<int>, greater<int>> q;
scanf("%d", &n);
for(int i = 0; i < n; i ++) {
scanf("%d", &s);
q.push(s);
}
while(q.size() > 1) {
int s1 = q.top();
q.pop();
int s2 = q.top();
q.pop();
q.push((s1 + s2) / 2);
}
printf("%d", q.top());
return 0;
}
-
A1128 N Queens Puzzle
题意:判断给定序列是否满足N皇后的解。
解法:判断是否在同一横线上(即seq[i] == seq[j]),再同一横线上则返回false。然后判断两点是否成对角线(即斜率为1)。注意不要用除法,因为整数除法有舍入,直接判断是否坐标差相等即可(abs(seq[j] - seq[i]) == (j - i))。
注意点:数组定义在全局后不需要申请,如果定义成局部变量,需要动态申请空间,否则会出错。
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 1010;
int seq[maxn];
bool isSolution(int n) {
for(int i = 1; i <= n; i ++) {
for(int j = i + 1; j <= n; j ++) {
if(seq[i] == seq[j]) {
return false;
}
if(abs(seq[j] - seq[i]) == (j - i)) {
return false;
}
}
}
return true;
}
int main() {
int k, n;
scanf("%d", &k);
for(int i = 0; i < k; i ++) {
scanf("%d", &n);
for(int j = 1; j <= n; j ++)
scanf("%d", &seq[j]);
if(isSolution(n)) printf("YES\n");
else printf("NO\n");
}
return 0;
}
-
A1129 Recommendation System
题意:根据历史访问信息,实时推荐前k个item。
解法:可以map按值排序,只需将将map中元素存到vector<pair<int, int>>数组中排序即可,但是两个测试点超时。
因此换一种方法,用可以自动按键排序的set。设置Item结构体,其中需要写一个operator<函数才能放入set,排序规则按题目要求先cnt再id。
将读入item的存放到items数组,用times数组记录item出现次数。然后第一个item之后每次输入item时,都需要推荐(实时性),输出此时至多前k个item。然后在set中找到当前的item并删除,因为它的cnt需要被更新(加1),在times数组更新cnt后,构造一个新的Item放入set。如此继续下去。
注意点:give to sth. 在某事上花时间。
#include<cstdio>
#include<set>
#include<map>
#include<algorithm>
using namespace std;
struct Item {
int id, cnt;
Item(int _id, int _cnt) : id(_id), cnt(_cnt) {}
bool operator < (const Item& b) const {
if(cnt != b.cnt) return cnt > b.cnt;
else return id < b.id;
}
};
const int maxn = 50010;
int items[maxn], times[maxn];
int main() {
int n, k, id;
set<Item> s;
scanf("%d %d", &n, &k);
for(int i = 0; i < n; i ++)
scanf("%d", &items[i]);
s.insert(Item(items[0], 1));
times[items[0]] = 1;
for(int i = 1; i < n; i ++) {
printf("%d:", items[i]);
int j = 0;
for(auto it = s.begin(); it != s.end() && j < k; it ++, j ++) {
printf(" %d", it->id);
}
if(s.find(Item(items[i], times[items[i]])) != s.end()) {
s.erase(Item(items[i], times[items[i]]));
}
times[items[i]] ++;
s.insert(Item(items[i], times[items[i]]));
printf("\n");
}
return 0;
}
-
A1132 Cut Integer
题意:判断一个数字能不能被它分成前后两段的数字的乘积整除。
分析:直接按要求计算,一开始以为会溢出,但发现是浮点错误。原因以下:
因此想到可能是后半段的数组可能全是0,出现了除0错误。
#include<cstdio>
#include<iostream>
#include<string>
using namespace std;
int main() {
int n;
scanf("%d", &n);
string num;
for(int i = 0; i < n; i ++) {
cin >> num;
string left = num.substr(0, num.size() / 2);
string right = num.substr(num.size() / 2);
int x = stoi(num);
int l = stoi(left);
int r = stoi(right);
if(r == 0) printf("No\n");
else if(x % (l * r) == 0) printf("Yes\n");
else printf("No\n");
}
return 0;
}
-
A1133 Splitting A Linked List
题意:链表排序。
解法:结构体Node中设置变量order表示链表的顺序。设置变量flag:flag == 0,表示小于0;flag == 1,表示小于等于K,flag == 2表示其它元素。初始化节点数组的flag和order都为maxn(其实只有将flag置为maxn就行了),让不在链表中的元素排到数组最后。
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 100010;
struct Node {
int addr;
int data;
int next;
int order;
int flag; //0: less0, 1: lessK, 2: moreK
} node[maxn];
bool cmp(Node a, Node b) {
if(a.flag != b.flag) return a.flag < b.flag;
else return a.order < b.order;
}
void init() {
for(int i = 0; i < maxn; i ++) {
node[i].flag = maxn;
// node[i].order = maxn;
}
}
int main() {
init();
int st, n, k, addr;
scanf("%d %d %d", &st, &n, &k);
for(int i = 0; i < n; i ++) {
scanf("%d", &addr);
node[addr].addr = addr;
scanf("%d %d", &node[addr].data, &node[addr].next);
}
int p = st, cnt = 0;
while(p != -1) {
node[p].order = cnt ++;
if(node[p].data < 0) node[p].flag = 0;
else if(node[p].data <= k) node[p].flag = 1;
else node[p].flag = 2;
p = node[p].next;
}
sort(node, node + maxn, cmp);
for(int i = 0; i < cnt; i ++) {
printf("%05d %d ", node[i].addr, node[i].data);
if(i < cnt - 1) printf("%05d\n", node[i + 1].addr);
else printf("-1\n");
}
return 0;
}
-
A1136 A Delayed Palindrome
题意:判断是否是延迟的回文数。
分析:一开始直接使用to_string()和stoi()完成加法,发现最后一个样例运行时错误。题目说不超过1000位,说明可能是大整数(应该就是最后一个测试用例)。因此实现大整数加法。通过。
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
bool isPalindromic(string num) {
int len = num.size();
for(int i = 0; i < len / 2; i ++)
if(num[i] != num[len - i - 1])
return false;
return true;
}
string add(string a, string b) {
string c;
reverse(a.begin(), a.end());
reverse(b.begin(), b.end());
int carry = 0;
for(int i = 0; i < a.length() || i < b.length(); i ++) {
int temp = a[i] - '0' + b[i] - '0' + carry;
c.insert(0, to_string(temp % 10));
carry = temp / 10;
}
if(carry != 0) c.insert(0, to_string(carry));
return c;
}
int main() {
string a;
cin >> a;
int cnt = 0;
while(cnt < 10) {
if(isPalindromic(a)) {
printf("%s is a palindromic number.\n", a.c_str());
break;
}
cnt ++;
string b = a;
reverse(b.begin(), b.end());
string c = add(a, b);
printf("%s + %s = %s\n", a.c_str(), b.c_str(), c.c_str());
a = c;
}
if(cnt == 10)
printf("Not found in 10 iterations.\n");
return 0;
}
-
A1137 Final Grading
题意:结构体排序,分多次输入不同成员变量。
解法:用map<string, int> idx建立id的唯一的整数映射。设置一个ans数组保存符合条件的元素,然后排序。
注意点:rounded up, 对x四舍五入的方法:int(x + 0.5);
#include<iostream>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;
struct node {
string id;
int Gp, Gm, Gf, G;
};
map<string, int> idx;
bool cmp(node a, node b) {
return a.G != b.G ? a.G > b.G : a.id < b.id;
}
int main() {
int p, m, n, score, cnt = 1;
scanf("%d %d %d", &p, &m, &n);
vector<node> v, ans;
string id;
for(int i = 0; i < p; i ++) {
cin >> id >> score;
if(score >= 200) {
v.push_back(node{id, score, -1, -1, 0});
idx[id] = cnt ++;
}
}
for(int i = 0; i < m; i ++) {
cin >> id >> score;
if(idx[id] != 0) {
v[idx[id] - 1].Gm = score;
}
}
for(int i = 0; i < n; i ++) {
cin >> id >> score;
if(idx[id] != 0) {
int temp = idx[id] - 1;
v[temp].Gf = v[temp].G = score;
if(v[temp].Gm > v[temp].Gf)
v[temp].G = int(v[temp].Gm * 0.4 + v[temp].Gf * 0.6 + 0.5);
}
}
for(int i = 0; i < v.size(); i ++)
if(v[i].G >= 60) ans.push_back(v[i]);
sort(ans.begin(), ans.end(), cmp);
for(int i = 0; i < ans.size(); i ++)
printf("%s %d %d %d %d\n", ans[i].id.c_str(), ans[i].Gp, ans[i].Gm, ans[i].Gf, ans[i].G);
return 0;
}
-
A1140 Look-and-say Sequence
题意:看说序列,用下一个序列描述上一个序列,一个元素跟着它的个数。
解法:关键是统计连续字符的个数: for(j = i; s[j] == s[i]; j ++);
#include<iostream>
using namespace std;
string getNext(string s) {
string ans;
int j;
for(int i = 0; i < s.length(); i = j) {
for(j = i; s[j] == s[i]; j ++);
ans += s[i];
ans += to_string(j - i);
}
return ans;
}
int main() {
string d;
int n;
cin >> d >> n;
for(int i = 0; i < n - 1; i ++) {
d = getNext(d);
}
printf("%s", d.c_str());
return 0;
}
-
A1141 PAT Ranking of Institutions
题意:排序题。
解法:用map将string映射成int得到整数id。
#include<cstdio>
#include<cctype>
#include<iostream>
#include<map>
#include<algorithm>
using namespace std;
const int maxn = 100010;
struct School {
string id;
int Bscore, Ascore, Tscore;
int score;
int rank;
int stuNum;
} school[maxn];
map<string, int> idx;
string toSmall(string name) {
for(int i = 0; i < name.size(); i ++)
name[i] = tolower(name[i]);
return name;
}
bool cmp(School a, School b) {
if(a.score != b.score) return a.score > b.score;
else if(a.stuNum != b.stuNum) return a.stuNum < b.stuNum;
else return a.id < b.id;
}
int main() {
int n, score, cnt = 1;
string id, name;
scanf("%d", &n);
for(int i = 1; i <= n; i ++) {
cin >> id >> score >> name;
name = toSmall(name);
if(idx[name] == 0) idx[name] = cnt ++;
school[idx[name]].id = name;
if(id[0] == 'B') school[idx[name]].Bscore += score;
else if(id[0] == 'A') school[idx[name]].Ascore += score;
else if(id[0] == 'T') school[idx[name]].Tscore += score;
school[idx[name]].stuNum ++;
}
for(int i = 1; i <= cnt - 1; i ++)
school[i].score = (int)(school[i].Bscore / 1.5 + school[i].Ascore + school[i].Tscore * 1.5);
sort(school + 1, school + cnt, cmp);
school[1].rank = 1;
for(int i = 2; i <= cnt - 1; i ++) {
if(school[i].score == school[i - 1].score)
school[i].rank = school[i - 1].rank;
else if(school[i].score < school[i - 1].score)
school[i].rank = i;
}
printf("%d\n", cnt - 1);
for(int i = 1; i <= cnt - 1; i ++)
printf("%d %s %d %d\n", school[i].rank, school[i].id.c_str(), school[i].score, school[i].stuNum);
return 0;
}
-
A1144 The Missing Number
题意:找到最小的没出现的整数。
解法:读入的数装入set,然后从1开始遍历查找。
注意点:while的括号里面的语句会先于循环主体执行。
#include<cstdio>
#include<set>
using namespace std;
int main() {
int n, num;
scanf("%d", &n);
set<int> s;
for(int i = 0; i < n; i ++) {
scanf("%d", &num);
s.insert(num);
}
int j = 1;
while(true) {
if(s.find(j) == s.end()) {
printf("%d", j);
break;
}
j ++;
}
return 0;
}
-
A1145 Hashing - Average Search Time
题意:hash和冲突的解决。读了几遍题目才明白意思。所谓比较次数,就是探测的次数。
解法:hash表+平方探测解决冲突。统计查找次数还是用二次探测法,每次探测算一次比较 ,注意当找到元素(hashTable[key] == x)或元素不存在(hashTable[key] == 0)时结束探测。
#include<cstdio>
const int maxn = 10001;
int hashTable[maxn] = {0};
bool isPrime(int n) {
if(n < 2) return false;
for(int i = 2; i * i <= n; i ++)
if(n % i == 0) return false;
return true;
}
int main() {
int MSize, n, m;
scanf("%d %d %d", &MSize, &n, &m);
while(isPrime(MSize) == false) MSize ++;
int x;
for(int i = 0; i < n; i ++) {
scanf("%d", &x);
int key = x % MSize;
if(hashTable[key] == 0) {
hashTable[key] = x;
}
else {
int step;
for(step = 1; step < MSize; step ++) {
key = (x + step * step) % MSize;
if(hashTable[key] == 0) {
hashTable[key] = x;
break;
}
}
if(step >= MSize) {
printf("%d cannot be inserted.\n", x);
}
}
}
int cnt = 0;
for(int i = 0; i < m; i ++) {
scanf("%d", &x);
for(int step = 0; step <= MSize; step ++) {
cnt ++;
int key = (x + step * step) % MSize;
if(hashTable[key] == x || hashTable[key] == 0) break;
}
}
printf("%.1f", cnt * 1.0 / m);
return 0;
}
-
A1148 Werewolf - Simple Version
MARK.
题意:狼人杀。有两人说谎,其中有一个是狼人。
解法:将每个人的说法保存到数组v中。设一个数组表示真实情况,1是好人,-1是狼人。枚举是狼人的两个人的所有情况。然后遍历每个人的说法v[k],如果这个人的说法和真实情况不符,即v[k] * a[abs(v[k])]为负数,则将这个人k加入说谎数组。最后如果说谎人数为2,且说谎的一个是好人一个时狼人则满足题目要求。
#include<iostream>
#include<vector>
using namespace std;
int main() {
int n;
cin >> n;
vector<int> v(n + 1);
for(int i = 1; i <= n; i ++)
cin >> v[i];
for(int i = 1; i <= n; i ++) {
for(int j = i + 1; j <= n; j ++) {
vector<int> lie, a(n + 1, 1); //说谎,狼人-1/好人1
a[i] = a[j] = -1;
for(int k = 1; k <= n; k ++)
if(v[k] * a[abs(v[k])] < 0) lie.push_back(k);
if(lie.size() == 2 && a[lie[0]] + a[lie[1]] == 0) {
cout << i << " " << j;
return 0;
}
}
}
cout << "No Solution";
return 0;
}
-
A1149 Dangerous Goods Packaging
题意:集合中出现了某物品不相容的物品则输出No。
解法:注意可能有一个物品有多个不相容物品,因此简单的使用map<int, int>不可行。因此使用map<int, set<int>>来记录不相容物品。对于每个测试集合的物品,判断其每个不相容物品是否出现在该集合中,如果出现则输出No,否则输出Yes。
#include<cstdio>
#include<map>
#include<set>
using namespace std;
map<int, set<int>> mp;
int main() {
int n, m, k, a, b;
scanf("%d %d", &n, &m);
for(int i = 0; i < n; i ++) {
scanf("%d %d", &a, &b);
mp[a].insert(b);
mp[b].insert(a);
}
for(int i = 0; i < m; i ++) {
scanf("%d", &k);
set<int> s;
for(int j = 0; j < k; j ++) {
scanf("%d", &a);
s.insert(a);
}
bool flag = false;
for(auto it1 : s) {
for(auto it2 : mp[it1]) {
if(s.find(it2) != s.end()) {
flag = true;
break;
}
}
}
if(flag) printf("No\n");
else printf("Yes\n");
}
return 0;
}
-
A1152 Google Recruitment
题意:找到数字串最左边的长度为K的质数。
解法:从左到右遍历,取出长度为K的子串,判断是否是质数。注意边界条件是i + K <= L,对应长度为L的子串。
#include<iostream>
using namespace std;
bool isPrime(int x) {
if(x < 2) return false;
for(int i = 2; i * i <= x; i ++)
if(x % i == 0) return false;
return true;
}
int main() {
int L, K;
string num;
cin >> L >> K >> num;
int i;
for(i = 0; i + K <= L; i ++)
if(isPrime(stoi(num.substr(i, K)))) {
cout << num.substr(i, K) << endl;
break;
}
if(i + K > L) cout << "404" << endl;
return 0;
}
-
A1153 Decode Registration Card of PAT
关键点:unordered_map效率高于map。map按值排序。
#include<cstdio>
#include<iostream>
#include<unordered_map>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn = 10010;
struct Student {
string id;
int score;
} stu[maxn];
bool cmp(Student a, Student b) {
if(a.score != b.score) return a.score > b.score;
else return a.id < b.id;
}
bool cmpMap(pair<string, int> a, pair<string, int> b) {
return a.second != b.second ? a.second > b.second : a.first < b.first;
}
int main() {
int n, m;
scanf("%d %d", &n, &m);
for(int i = 0; i < n; i ++) {
cin >> stu[i].id >> stu[i].score;
}
sort(stu, stu + n, cmp);
int type;
string cmd;
for(int k = 0; k < m; k ++) {
cin >> type >> cmd;
printf("Case %d: %d %s\n", k + 1, type, cmd.c_str());
int cnt = 0, sum = 0;
if(type == 1) {
bool flag = false;
for(int i = 0; i < n; i ++) {
if(stu[i].id[0] == cmd[0]) {
flag = true;
printf("%s %d\n", stu[i].id.c_str(), stu[i].score);
}
}
if(flag == false) printf("NA\n");
}
else if(type == 2) {
for(int i = 0; i < n; i ++) {
if(stu[i].id.substr(1, 3) == cmd) {
cnt ++;
sum += stu[i].score;
}
}
if(cnt != 0) printf("%d %d\n", cnt, sum);
else printf("NA\n");
}
else if(type == 3) {
unordered_map<string, int> mp;
for(int i = 0; i < n; i ++) {
if(stu[i].id.substr(4, 6) == cmd) {
mp[stu[i].id.substr(1, 3)] ++;
}
}
vector<pair<string, int>> v(mp.begin(), mp.end());
sort(v.begin(), v.end(), cmpMap);
for(int i = 0; i < v.size(); i ++)
printf("%s %d\n", v[i].first.c_str(), v[i].second);
if(v.size() == 0) printf("NA\n");
}
}
return 0;
}