第一章、字符串处理
1001 A+B Format (20 分)
- 题意 :将整数转换成标准格式
- 思路 :从后往前遍历字符串进行模拟,每三个数字加一个逗号,但不能是在最前面加逗号,也不能是加在负号后面
- 语法 :使用string和to_string函数不需要头文件
#include <iostream>
using namespace std;
int main()
{
int a, b;
cin >> a >> b;
string num = to_string(a + b);
string ans = "";
for (int i = num.size() - 1, j = 0; i >= 0; i -- )
{
ans = num[i] + ans;
++ j;
if (j % 3 == 0 && i && num[i - 1] != '-') ans = "," + ans;
}
cout << ans;
return 0;
}
1005 Spell It Right (20 分)
- 题意 :得到输入数的各位之和后按位输出分别的英文
- 语法 :行末无空格,可以先输出第一位后,分别输出一个空格加每一位
#include <iostream>
using namespace std;
string word[] = {"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"};
int main()
{
string n;
cin >> n;
int s = 0;
for (auto c : n) s += c - '0';
string str = to_string(s);
cout << word[str[0] - '0'];
for (int i = 1; i < str.size(); i ++ ) cout << ' ' << word[str[i] - '0'];
return 0;
}
1006 Sign In and Sign Out (25 分)
- 题意 :在输入的每个第二个字符串中找最小的,第三个找最大的,输出它们分别对应的第一个字符串
#include <iostream>
using namespace std;
int main()
{
string open_id, open_time;
string close_id, close_time;
int m;
cin >> m;
for (int i = 0; i < m; i ++ )
{
string id, in_time, out_time;
cin >> id >> in_time >> out_time;
// 更新
if (!i || in_time < open_time)
{
open_id = id;
open_time = in_time;
}
if (!i || out_time > close_time)
{
close_id = id;
close_time = out_time;
}
}
cout << open_id << ' ' << close_id;
return 0;
}
1035 Password (20 分)
- 题意 :输入的每行的第二个字符串中按照题意替换字符,并且记录被替换过的这两个字符串,按要求输出
- 思路 :数组记录即可,因为是按顺序一一对应的
- 语法 :puts和printf在这种时候比较方便。
#include <iostream>
using namespace std;
const int N = 1010;
string name[N], pwd[N];
string change(string str)
{
string res;
for (auto c : str)
if (c == '1') res += '@';
else if (c == '0') res += '%';
else if (c == 'l') res += 'L';
else if (c == 'O') res += 'o';
else res += c;
return res;
}
int main()
{
int n;
cin >> n;
int m = 0;
for (int i = 0; i < n; i ++ )
{
string a, b;
cin >> a >> b;
string c = change(b);
if (b != c) name[m] = a, pwd[m ++ ] = c;
}
if (!m)
{
if (n == 1) puts("There is 1 account and no account is modified");
else printf("There are %d accounts and no account is modified", n);
}
else
{
cout << m << endl;
for (int i = 0; i < m; i ++ ) cout << name[i] << ' ' << pwd[i] << endl;
}
return 0;
}
1050 String Subtraction (20 分)
- 题意 :给两个字符串,在第一个字符串中将在第二个中出现过的字符全部删除
- 语法 : g e t l i n e getline getline函数在 i o s t r e a m iostream iostream头文件中;unordered_set的count函数和insert函数
#include <iostream>
#include <unordered_set>
using namespace std;
int main()
{
string s1, s2;
getline(cin, s1);
getline(cin, s2);
unordered_set<char> hash;
for (auto c : s2) hash.insert(c);
string res;
for (auto c : s1)
if (!hash.count(c))
res += c;
cout << res;
return 0;
}
1061 Dating (20 分)
- 题意 :captive letter大写字母;case sensitive区分大小写;common共同的
- 题意 :先找到第一二个字符串中第一个一样的且符合条件的大写字母,然后是第二个一样的且符合条件大写字母,然后找第三四个字符串中第一个符合条件且一样的字母
- 思路 :要看清题目背后含义,字母范围;在第一个和第二个的输出中,如果写在同一个循环里,第一个满足后用了bool还不够,还要加一个continue,否则直接进入了第二个判断条件,而采用标准写法用两个while就没有这个问题;
- 语法 :时间题常见用printf的%02d;printf选择句式;ASCII码中从小到大分别是,数字,大写字母,小写字母;或中的与不需要括号;a[k] - ‘A’ + 10
#include <iostream>
using namespace std;
int main()
{
string a, b, c, d;
cin >> a >> b >> c >> d;
int k = 0;
while (true)
{
if (a[k] == b[k] && 'A' <= a[k] && 'G' >= a[k]) break;
k ++ ;
}
char weekdays[7][4] = {"MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"};
printf("%s ", weekdays[a[k] - 'A']);
k ++ ;
while (true)
{
if (a[k] == b[k] && (a[k] >= '0' && a[k] <= '9' || a[k] >= 'A' && a[k] <= 'N')) break;
k ++ ;
}
printf("%02d:", a[k] <= '9' ? a[k] - '0' : a[k] - 'A' + 10);
for (int i = 0;; i ++ )
if (c[i] == d[i] && (c[i] >= 'a' && c[i] <= 'z' || c[i] >= 'A' && c[i] <= 'Z'))
{
printf("%02d", i);
break;
}
return 0;
}
1073 Scientific Notation (20 分)
- 题意 :科学计数法转数字
- 思路 :当科学计数法系数>0时,有可能不仅无法加零,还去不了小数点;注意题目有个关键地方,无论这个数是正负,第一位是符号位
- 语法 :string的find函数;substr若只有一个参数,那个参数是pos,返回包含pos在内后面的整个字符串;string函数,先长度后内容
#include <iostream>
using namespace std;
int main()
{
string s;
cin >> s;
if (s[0] == '-') cout << '-';
int k = s.find('E');
string a = s[1] + s.substr(3, k - 3);
int b = stoi(s.substr(k + 1));
if (b <= 0) cout << "0." << string(- b - 1, '0');
else if (b < a.size() - 1) a = a.substr(0, b + 1) + '.' + a.substr(b + 1);
else a += string(b - a.size() + 1, '0');
cout << a;
return 0;
}
1077 Kuchiguse (20 分)
- 题意 :给n个字符串,找这n个字符串最长的公共后缀( 2 < = N < = 100 2<=N<=100 2<=N<=100, m a x l e n < = 256 maxlen <= 256 maxlen<=256)
- 语法 :与getline搭配使用getchar!reverse在algorithm中;substr只传一个参数的妙用,后缀
#include <iostream>
using namespace std;
const int N = 110;
string s[N];
int main()
{
int n;
cin >> n;
getchar();
for (int i = 0; i < n; i ++ ) getline(cin, s[i]);
for (int k = s[0].size(); k; k -- )
{
string sf = s[0].substr(s[0].size() - k);
bool is_matched = true;
for (int i = 1; i < n; i ++ )
if (s[i].size() < k || s[i].substr(s[i].size() - k) != sf)
{
is_matched = false;
break;
}
if (is_matched)
{
cout << sf;
return 0;
}
}
cout << "nai";
return 0;
}
1084 Broken Keyboard (20 分)
- 题意 :The English letters must be capitalized英文字母必须大写
- 题意 :给两个字符串,找第二个字符串中在第一个中没有出现的字符,无视大小写
- 思路 :双指针即可,b中有的a中一定有,反之不一定,且按顺序,利用好这种性质,a为主指针,将b中与a一一比对;为了防止数组越界,要在b中最后加上一个a中没有出现过的字符
- 语法 :char = toupper(char);ASCII码才127之间,且可以直接以char当数组下标;让一个数组全部都是某个具体数值的方法
#include <iostream>
using namespace std;
int main()
{
string a, b;
cin >> a >> b;
bool st[200] = {0};
b += '#';
for (int i = 0, j = 0; i < a.size(); i ++ )
{
char x = toupper(a[i]), y = toupper(b[j]);
if (x == y) j ++ ;
else
{
if (!st[x]) st[x] = true, cout << x;
}
}
return 0;
}
1108 Finding Average (20 分)
- 题意 :number和numbers
- 题意 :输入n个字符串,判断分别是否是合法数字(大小,小数点后位数,无效字符)
- 思路 :看小数点后是否合法时,如果点在最后一位,num.size() - k就会是1,在倒数第二位,就会是2,倒数第三位等于3,在倒数第三位时后面有两位有效数字,所以大于三,就多于两位有效数字
- 语法 :stof(float实数)可以帮我们判断输入字符串是否合法,如果不合法会抛出异常,所以只要写try,catch语句,如果是合法数字,再判断是否在正负一千以内,小数点后是否最多两位;但这个函数有一个问题5.2abc也被算作合法数字,它会看这个字符串的前几位能否构成合法实数, 如果能,它就只用前几位,所以这里还要判断最终位数。size_t是记录用了几个字符,如果用的字符的数量小于num.size,说明就是5.2abc形式,也不是合法的;**catch(…)**表示接收任何类型的异常;string.find ,k!=-1就是存在小数点;string.c_str();且以上这些不需要其它额外的头文件
#include <iostream>
using namespace std;
int main()
{
int n;
cin >> n;
double sum = 0;
int cnt = 0;
while (n -- )
{
string num;
cin >> num;
double x;
bool success = true;
try
{
size_t idx;
x = stof(num, &idx);
if (idx < num.size()) success = false;
}
catch(...)
{
success = false;
}
if (x < -1000 || x > 1000) success = false;
int k = num.find('.');
if (k != -1 && num.size() - k > 3) success = false;
if (success) cnt ++ , sum += x;
else printf("ERROR: %s is not a legal number\n", num.c_str());
}
if (cnt > 1) printf("The average of %d numbers is %.2lf", cnt, sum / cnt);
else if (cnt == 1) printf("The average of 1 number is %.2lf", sum);
else printf("The average of 0 numbers is Undefined");
return 0;
}
1124 Raffle for Weibo Followers (20 分)
- 题意 :给n个字符串,输出从开始位置每隔m个位置的字符串,要跳过已经被输出过的
- 思路 :模拟就是从第一个开始的位置输出,然后每次跳到n个位置后,如果跳到的位置已经被输出过,那就跳过;索性用数组记录位置对应的字符串,就不用for了;用set判断是否已经被输出过以及有没有输出过字符串。
#include <iostream>
#include <unordered_set>
using namespace std;
const int N = 1e3 + 10;
string name[N];
int main()
{
int m, n, s;
cin >> m >> n >> s;
unordered_set<string> se;
for (int i = 1; i <= m; i ++ ) cin >> name[i];
int k = s;
while (k <= m)
{
if (se.find(name[k]) != se.end()) k ++ ;
else
{
cout << name[k] << endl;
se.insert(name[k]);
k += n;
}
}
if (se.empty()) cout << "Keep going...";
return 0;
}
第二章、高精度
1002 A+B for Polynomials (25 分)
- 题意 :给两个多项式,输出两个多项式相加结果的系数和次数
- 思路 :用double数组记录多项式,正好数组下标是整数,系数是double
#include <iostream>
using namespace std;
const int N = 1010;
double a[N], b[N], c[N];
int main()
{
int k;
cin >> k;
while (k -- )
{
int ex;
double co;
cin >> ex >> co;
a[ex] = co;
}
cin >> k;
while (k -- )
{
int ex;
double co;
cin >> ex >> co;
b[ex] = co;
}
for (int i = 0; i < N; i ++ ) c[i] = a[i] + b[i];
k = 0;
for (int i = 0; i < N; i ++ )
if (c[i])
k ++ ;
cout << k;
for (int i = N - 1; i >= 0; i -- )
if (c[i])
printf(" %d %.1lf", i, c[i]);
return 0;
}
1009 Product of Polynomials (25 分)
- 题意 :给两个多项式,输出两个多项式相乘结果的系数和次数
- 语法 :使用函数化解这个不同的容器相同操作的尴尬;正确认知数组实际应有的容量,尽量开大
#include <iostream>
using namespace std;
const int N = 1010, M = N * 2;
double a[N], b[N], c[M];
void input(double a[])
{
int k;
cin >> k;
while (k -- )
{
int n;
double v;
cin >> n >> v;
a[n] = v;
}
}
int main()
{
input(a);
input(b);
for (int i = 0; i < N; i ++ )
for (int j = 0; j < N; j ++ )
c[i + j] += a[i] * b[j];
int k = 0;
for (int i = 0; i < M; i ++ )
if (c[i])
k ++ ;
cout << k;
for (int i = M - 1; i >= 0; i -- )
if (c[i])
printf(" %d %.1lf", i, c[i]);
return 0;
}
1023 Have Fun with Numbers (20 分)
- 题意 :将n乘以二后得到的数的每一位数字是否和n中个数一样
- 思路 :高精度加法(整数) 就是在int和long long都存不下来时用;个位存在a[0]的位置(倒着放);如何判断两个vector数组中无关顺序的情况下所存数一样呢 ?排序后直接比较。
- 语法 :vector之间 支持比较运算,可以按照字典序判断两个序列大小关系;sort函数在algorithm头文件中。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
string A;
vector<int> a;
cin >> A;
for (int i = A.size() - 1; i >= 0; i -- ) a.push_back(A[i] - '0');
vector<int> b;
int t = 0;
for (int i = 0; i < a.size(); i ++ )
{
int s = a[i] + a[i] + t;
b.push_back(s % 10);
t = s / 10;
}
if (t) b.push_back(1);
vector<int> c = b;
sort(c.begin(), c.end());
sort(a.begin(), a.end());
if (a == c) puts("Yes");
else puts("No");
for (int i = b.size() - 1; i >= 0; i -- ) cout << b[i];
return 0;
}
1058 A+B in Hogwarts (20 分)
-
思路 :实则就是进位制的操作,不用if特判
-
语法 :scanf和printf的妙用
#include <iostream>
using namespace std;
int main()
{
int a, b, c, d, e, f;
scanf("%d.%d.%d %d.%d.%d", &a, &b, &c, &d, &e, &f);
a += d, b += e, c += f;
b += c / 29, c %= 29;
a += b / 17, b %= 17;
printf("%d.%d.%d", a, b, c);
return 0;
}
1136 A Delayed Palindrome (20 分)
- 题意 :输入一数,循环将其与逆序相加得到一新数,直到新数为回文串
- 思路 :注意每次循环里面是先check再进行后续操作(包括等式)的,否则会wa,想象比如输入的就是回文数的情况;且第十次出去的如果是的话,也是回文数要输出;一般先放最低位到vector中;高精度加法的写法;函数化程序
- 语法 :将一个vector逆序复制给另一个vector;从string转换到vector的时候记得-‘0’
#include <iostream>
#include <vector>
using namespace std;
bool check(vector<int> A)
{
for (int i = 0, j = A.size() - 1; i < j; i ++ , j -- )
if (A[i] != A[j])
return false;
return true;
}
void print(vector<int> A)
{
for (int i = A.size() - 1; i >= 0; i -- )
cout << A[i];
}
vector<int> add(vector<int> A, vector<int> B)
{
vector<int> C;
for (int i = 0, t = 0; i < A.size() || i < B.size() || t; i ++ )
{
if (i < A.size()) t += A[i];
if (i < B.size()) t += B[i];
C.push_back(t % 10);
t /= 10;
}
return C;
}
int main()
{
string a;
cin >> a;
vector<int> A;
for (int i = 0; i < a.size(); i ++ ) A.push_back(a[a.size() - 1 - i] - '0');
for (int i = 0; i < 10; i ++ )
{
if (check(A)) break;
vector<int> B(A.rbegin(), A.rend());
print(A), cout << " + ", print(B), cout << " = ";
A = add(A, B);
print(A), cout << endl;
}
if (check(A)) print(A), cout << " is a palindromic number.";
else cout << "Not found in 10 iterations.";
return 0;
}
第三章、进位制
1010 Radix (25 分)
- 题意 :radix进制
- 题意 :给两个数和其中一个数的进制,问另一个数能否在某一进制下与这数相等
- 思路 :如果tag等于2就交换,最后还是只需要处理tag为1这种情况,这种思路值得学习;第一步,将n1转换成十进制,考虑这是否能存下,n1不超过十位数字,所以最大是十个z,也就是三十六进制,十个z小于1后面十个0,也就是小于 3 6 10 36^{10} 3610,3e15多些,也就是说可以用long long存下;第二步,判断n2在什么进制下等于target,注意n2可能不止36进制,比如n2是 ( 10 ) b = b (10)_b=b (10)b=b,n1最大又是3e15,所以我们最大可以弄一个3e15次方,所以枚举的时候不止枚举到36次 ,也就是说这个枚举的区间非常大,我们就想到能否能用二分来求呢,我们发现,当枚举的进制变大时,n2也会变大,这是一个单调的过程,所以我们可以用二分来求这个进制;
- 二分需要一个左右边界,右边界是target+1,左边界应该等于n2的最大的这一位加1
- 在calc中,res可能会爆long long,如果太大,大于1e16了已经,我们知道n1最大值是3e15,此时一定无解,则直接返回1e18;注意calc中参数的进制r也是要用long long的
- r如果直接取target,那么6 6 1 10这个样例会返回6,但答案是7。
- 注意代码中多次将int主动转成long long的情形
- 两个数相乘的结果可能long long也存不下,溢出可能变成负数也可能变成正数,所以要用double
- 语法 :swap函数在algoeithm 头文件中
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
int get(char c)
{
if (c <= '9') return c - '0';
return c - 'a' + 10;
}
ll calc(string n, ll r)
{
ll res = 0;
for (auto c : n)
{
if ((double)res * r + get(c) > 1e16) return 1e18;
res = res * r + get(c);
}
return res;
}
int main()
{
string n1, n2;
cin >> n1 >> n2;
int tag, radix;
cin >> tag >> radix;
if (tag == 2) swap(n1, n2);
ll target = calc(n1, radix);
ll l = 0, r = target + 1;
// ll l = 0, r = max(target, 36ll);
for (auto c : n2) l = max(l, (ll)get(c) + 1);
while (l < r)
{
ll mid = l + r >> 1;
if (calc(n2, mid) >= target) r = mid; // == problem!
else l = mid + 1;
}
if (calc(n2, r) == target) cout << r;
else cout << "Impossible";
return 0;
}
1015 Reversible Primes (20 分)
- 题意 :首先判断N是不是质数。然后将N转成D进制数,将D进制数翻转后,转回十进制数,看得到的这个数是否是质数。
- 思路 : n n n% d d d是n在d进制下最后一位数,也就是在d进制下的个位,在翻转后,这位应该是第一位,将翻转后的结果变成十进制时是要从最高位开始做。这样就将最后三步化为了一步。
- 语法 :逗号表达式的值是最后一个的值; N N N最大是 1 0 5 10^5 105,那么如果是二进制的话就会有十几位,十五六位,所以得用 l o n g l o n g long long longlong存转换之后的结果。
#include <iostream>
using namespace std;
typedef long long LL;
bool is_prime(int n)
{
if (n == 1) return false;
for (int i = 2; i * i <= n; i ++ )
if (n % i == 0)
return false;
return true;
}
bool check(int n, int d)
{
if (!is_prime(n)) return false;
LL r = 0;
while (n)
{
r = r * d + n % d;
n /= d;
}
return is_prime(r);
}
int main()
{
int n, d;
while (cin >> n >> d, n >= 1)
{
if (check(n, d)) puts("Yes");
else puts("No");
}
return 0;
}
1019 General Palindromic Number (20 分)
- 题意 :给出一个数和一个进制,判断这个数在这个进制下的结果是否是回文数。
- 思路 :判断回文数(i只要<j就可以了);十进制转其它进制,用vector存更方便;十进制转其它进制,注意n为0的情况要特殊讨论;十进制转其它进制时,先得到的是其它进制下的最低位,因为它最先被放入vector,且在输出其它进制下的这个数时,是从高位向低位输出,所以先从vector的最后一位开始输出。
- 语法 :reverse函数在algorithm头文件;使用vector记得加头文件vector;vector最后一个元素,back()
#include <iostream>
#include <vector>
using namespace std;
vector<int> nums;
bool check()
{
for (int i = 0, j = nums.size() - 1; i < j; i ++ , j -- )
if (nums[i] != nums[j])
return false;
return true;
}
int main()
{
int n, b;
cin >> n >> b;
if (!n) nums.push_back(0);
while (n) nums.push_back(n % b), n /= b;
if (check()) puts("Yes");
else puts("No");
cout << nums.back();
for (int i = nums.size() - 2; i >= 0; i -- ) cout << ' ' << nums[i];
return 0;
}
1027 Colors in Mars (20 分)
- 题意 :将输入的十进制数转为十三进制数
- 思路 :注意这里输入的十进制数最大为168,意味着转化为十三进制后最多只有两个数字,这也恰好可以解决题目要求的如果只有一位数字必须左添0,也就是说无论如何输出的都是两位数字的十三进制数;注意这种将十进制数转为大于十的进制数的“get“方式。
- 语法 :int转char
#include <iostream>
using namespace std;
int a[3];
char get(int x)
{
if (x > 9) return 'A' + x - 10;
return '0' + x;
}
int main()
{
for (int i = 0; i < 3; i ++ ) cin >> a[i];
cout << '#';
for (int i = 0; i < 3; i ++ ) cout << get(a[i] / 13) << get(a[i] % 13);
return 0;
}
1100 Mars Numbers (20 分)
- 思路 :重要的一点是高进制和低进制的英文单词没有重复,所以可以直接连接在同一个数组中
- 语法 :stringstream头文件为sstream
#include <iostream>
#include <sstream>
using namespace std;
char names[][5] = {"tret", "jan", "feb", "mar", "apr", "may", "jun", "jly", "aug", "sep", "oct", "nov", "dec", "tam", "hel", "maa", "huh", "tou", "kes", "hei", "elo", "syy", "lok", "mer", "jou"};
int get(string word)
{
for (int i = 0; i < 25; i ++ )
if (names[i] == word)
{
if (i < 13) return i;
return 13 * (i - 12);
}
return -1; // 一定不会执行
}
int main()
{
int T;
cin >> T;
getchar();
while (T -- )
{
string line;
getline(cin, line);
stringstream ssin(line);
if (line[0] <= '9')
{
int v;
ssin >> v;
if (v < 13) cout << names[v] << endl;
else
{
cout << names[12 + v / 13];
if (v % 13 != 0) cout << " " << names[v % 13];
cout << endl;
}
}
else
{
string word;
int res = 0;
while (ssin >> word) res += get(word);
cout << res << endl;
}
}
}
第四章、排序
1012 The Best Rank (25 分)
- 题意 :给ID和3门成绩,计算其平均分A,输出每位学生最好的排名,A>C>M>E
- 思路 :如果将所需的若干个元素中使第一个元素为后几个的平均值;容器内二分找值;题目所给ACME决定了搜索顺序,因此决定了容器顺序;二分时,如果是倒序的,就应该找最前面的,这里我们为了省事不写cmp说明是从小到大的,那么我们要找的就是最后一个,最后一个等于x的数的位置,然后如果说r是a.size() - 1,说明排名是第一,那么返回1,也就是说返回值是a.size() - r
- 语法 :round函数四舍五入,头文件是cmath;map的count用来找是否存在这个左值;int t[4]= {0];数组内统一初始值
#include <iostream>
#include <vector>
#include <unordered_map>
#include <algorithm>
#include <cmath>
using namespace std;
unordered_map<string, vector<int>> grades;
vector<int> q[4]; // A C M E
int get_grade(vector<int> &a, int x)
{
int l = 0, r = a.size() - 1;
while (l < r)
{
int mid = (l + r + 1) >> 1;
if (a[mid] <= x) l = mid;
else r = mid - 1;
}
return a.size() - r;
}
int main()
{
int n, m;
cin >> n >> m;
for (int i = 0; i < n; i ++ )
{
string id;
cin >> id;
int t[4] = {0};
for (int j = 1; j < 4; j ++ )
{
cin >> t[j];
t[0] += t[j];
}
t[0] = round(t[0] / 3.0);
for (int j = 0; j < 4; j ++ )
{
grades[id].push_back(t[j]);
q[j].push_back(t[j]);
}
}
for (int i = 0; i < 4; i ++ ) sort(q[i].begin(), q[i].end());
char names[] = "ACME";
while (m -- )
{
string id;
cin >> id;
if (grades.count(id) == 0) puts("N/A");
else
{
int res = n + 1;
char c;
for (int i = 0; i < 4; i ++ )
{
int rank = get_grade(q[i], grades[id][i]);
// int rank = 1 + n - (upper_bound(q[i].begin(), q[i].end(), grades[id][i]) - q[i].begin()); // 在vector要逆序的情况下
if (res > rank)
{
res = rank;
c = names[i];
}
}
cout << res << ' ' << c << endl;
}
}
}
第五章、树
第六章、图论
1003 Emergency (25 分)
- 题意 :求无向图中最短路的数量,以及在最短路情况下,点权之和最大是多少
- 思路 :dijkstra的扩展一般在第三步“用t更新其它点“;spfa不能用来求最短路的数量(因为每个点可能被更新多次);假设有三个点可以走到终点x,那么从起点s走到x的路径分为三类,s->1->x…,如果d1<d2<d3,最短距离的数量就是走到第一个点的数量,如果d1=d2<d3,前两个相加,同理,求最短路情况下点权和最大,就是三者取max(如果三者相同);cnt数组记录从起点走到i的最短路径数量;sum数组记录从起点到i的最大点权
- 语法 :如果点数<=1000,邻接矩阵就没有问题,>=1e4就一定要邻接表存;
#include <iostream>
#include <cstring>
using namespace std;
const int N = 510;
int n, m, S, T;
int w[N], g[N][N];
int cnt[N], sum[N];
int dist[N];
bool st[N];
void dijkstra()
{
memset(dist, 0x3f, sizeof dist); // 初始化
dist[S] = 0, cnt[S] = 1, sum[S] = w[S];
for (int i = 0; i < n - 1; i ++ )
{
int t = -1;
for (int j = 0; j < n; j ++ )
if (!st[j] && (t == -1 || dist[t] > dist[j]))
t = j;
st[t] = true; // 标记
for (int j = 0; j < n; j ++ )
if (dist[j] > dist[t] + g[t][j])
{
dist[j] = dist[t] + g[t][j];
cnt[j] = cnt[t];
sum[j] = sum[t] + w[j];
}
else if (dist[j] == dist[t] + g[t][j])
{
cnt[j] += cnt[t];
sum[j] = max(sum[j], sum[t] + w[j]);
}
}
}
int main()
{
cin >> n >> m >> S >> T;
for (int i = 0; i < n; i ++ ) cin >> w[i];
memset(g, 0x3f, sizeof g); // 初始化
while (m -- )
{
int a, b, c;
cin >> a >> b >> c;
g[a][b] = g[b][a] = min(g[a][b], c); // 无向图
}
dijkstra();
cout << cnt[T] << ' ' << sum[T];
return 0;
}
- 思路 :dijkstra中在循环for或者while的外面初始化时,起点的st不要设成true!堆优化版在一个点被更新松弛后将它放入优先队列内
- 语法 :堆优化版写成链式前向星,M开成N*N
// 堆优化版
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
const int N = 510, M = N * N; // 注意M大小
typedef pair<int, int> pii;
int h[N], w[M], e[M], ne[M], idx;
int wt[N];
int dist[N];
bool st[N];
int cnt[N], sum[N];
int n, m, S, T;
void add(int a, int b, int c)
{
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
}
void dijkstra()
{
memset(dist, 0x3f, sizeof dist);
dist[S] = 0;
cnt[S] = 1, sum[S] = wt[S];
priority_queue<pii, vector<pii>, greater<pii>> heap;
heap.push({0, S});
// st[S] = true; 注意!!!
while (heap.size())
{
auto t = heap.top();
heap.pop();
int ver = t.second, distance = t.first;
if (st[ver]) continue;
st[ver] = true;
for (int i = h[ver]; i != -1; i = ne[i])
{
int j = e[i];
if (dist[j] > dist[ver] + w[i])
{
dist[j] = dist[ver] + w[i];
cnt[j] = cnt[ver];
sum[j] = sum[ver] + wt[j];
heap.push({dist[j], j}); // 被更新松弛了的点要放入优先队列内
}
else if (dist[j] == dist[ver] + w[i])
{
cnt[j] += cnt[ver];
sum[j] = max(sum[j], sum[ver] + wt[j]);
}
}
}
}
int main()
{
memset(h, -1, sizeof h);
cin >> n >> m >> S >> T;
for (int i = 0; i < n; i ++ ) cin >> wt[i];
while (m -- )
{
int a, b, c;
cin >> a >> b >> c;
add(a, b, c);
add(b, a, c);
}
dijkstra();
cout << cnt[T] << ' ' << sum[T];
return 0;
}
第七章、数学
1081 Rational Sum (20 分)
- 题意 :rationnal numbers有理数;numerator/denominator分子/分母;integer part整数部分;fractional part小数部分
- 题意 :给n个分数,求和,要写成真分数且约分
- 思路 :初始化a为0,b为1;输出时 :如果分母是1,直接输出整数部分就可以;如果a>b,说明有整数部分和小数部分;pat上分子和分母数据范围是long int,相当于是int,而acwing是long long,如果没有中间那步会溢出,因此分母要变成b和d的最小公倍数,找到b和d的最大公约数,那么分母就是b/最大公约数再*d(原先应该是b *d),分子是…(原先是a * d + b * c),但是分子式子的前半部分是由d/t而不是a/t
- 语法 :gcd模版;scanf时如果是负数这个符号是在分子上读入的
#include <iostream>
using namespace std;
typedef long long LL;
LL gcd(LL a, LL b)
{
return b ? gcd(b, a % b) : a;
}
int main()
{
int n;
cin >> n;
LL a = 0, b = 1;
for (int i = 0; i < n; i ++ )
{
LL c, d;
scanf("%lld/%lld", &c, &d);
LL t = gcd(c, d);
c /= t, d /= t;
t = gcd(b, d);
a = d / t * a + b / t * c;
b = b / t * d;
t = gcd(a, b);
a /= t, b /= t;
}
if (b == 1) cout << a;
else
{
if (a > b) printf("%lld ", a / b), a %= b;
printf("%lld/%lld", a, b);
}
return 0;
}
1088 Rational Arithmetic (20 分)
- 题意 :给两个分数,分别输出加减乘除式子,注意分数要转成真分数,给的可能是假分数
- 思路 :打印时,先约分,然后判断分母是否为负,然后判断分子是否为负决定是否需要输出两个半括号,然后如果分母是1一种情况,否则要看是否是假分数,假分数时注意是abs,因为这道题会出现分子为负也可能出现分母为负的情况
#include <iostream>
using namespace std;
typedef long long LL;
LL gcd(LL a, LL b)
{
return b ? gcd(b, a % b) : a;
}
void print(LL a, LL b)
{
LL t = gcd(a, b);
a /= t, b /= t;
if (b < 0) a *= -1, b *= -1;
bool is_minus = a < 0;
if (is_minus) cout << "(";
if (b == 1) cout << a;
else
{
if (abs(a) > b) printf("%lld ", a / b), a = abs(a) % b;
printf("%lld/%lld", a , b);
}
if (is_minus) cout << ")";
}
void add(LL a, LL b, LL c, LL d)
{
print(a, b), cout << " + ", print(c, d), cout << " = ";
a = a * d + b * c;
b = b * d;
print(a, b), cout << endl;
}
void sub(LL a, LL b, LL c, LL d)
{
print(a, b), cout << " - ", print(c, d), cout << " = ";
a = a * d - b * c;
b = b * d;
print(a, b), cout << endl;
}
void mul(LL a, LL b, LL c, LL d)
{
print(a, b), cout << " * ", print(c, d), cout << " = ";
a = a * c;
b = b * d;
print(a, b), cout << endl;
}
void div(LL a, LL b, LL c, LL d)
{
print(a, b), cout << " / ", print(c, d), cout << " = ";
if (!c) puts("Inf");
else
{
a = a * d;
b = b * c;
print(a, b), cout << endl;
}
}
int main()
{
LL a, b, c, d;
scanf("%lld/%lld %lld/%lld", &a, &b, &c, &d);
add(a, b, c, d);
sub(a, b, c, d);
mul(a, b, c, d);
div(a, b, c, d);
return 0;
}
1096 Consecutive Factors (20 分)
- 题意 :给一数,求最长连续因子
- 思路 :先枚举起始位置,然后枚举长度;注意有可能只有它本身的情况
- 语法 : 2 31 2^{31} 231还是int范围;一直循环到连续断了,就直接退出for循环
#include <iostream>
#include <vector>
using namespace std;
int main()
{
int n;
cin >> n;
vector<int> res;
for (int i = 2; i * i <= n; i ++ )
if (n % i == 0)
{
vector<int> seq;
for (int m = n, j = i; m % j == 0; j ++ )
{
seq.push_back(j);
m /= j;
}
if (seq.size() > res.size()) res = seq;
}
if (res.empty()) res.push_back(n);
cout << res.size() << endl;
cout << res[0];
for (int i = 1; i < res.size(); i ++ ) cout << "*" << res[i];
return 0;
}
1104 Sum of Number Segments (20 分)
- 语法 :i和n-i+1都是 1 0 5 10^5 105,相乘有 1 0 10 10^{10} 1010,会超过int,所以那个公式写的时候尽可能把double写到前面,如果写到后面会溢出;(精度?)long double输出时是%Lf
#include <iostream>
using namespace std;
int main()
{
int n;
cin >> n;
long double res = 0;
for (int i = 1; i <= n; i ++ )
{
long double x;
cin >> x;
res += x * i * (n - i + 1);
}
printf("%.2Lf", res);
return 0;
}
#include <iostream>
using namespace std;
typedef long long ll;
int main()
{
int n;
cin >> n;
ll res = 0;
for (int i = 1; i <= n; i ++ )
{
double x;
cin >> x;
res += (ll)(1000 * x) * i * (n - i + 1); // 乘1000放大数字,避免精度的影响,注意括号
}
printf("%.2lf", res / 1000.0); // 加上.0可以转化成小数
return 0;
}
1112 Stucked Keyboard (20 分)
- 题意 :给k和一字符串,字符串中连续出现k次的为坏
- 思路 :用原字符串判断某个键(数量固定)是否坏;遍历原字符串,每种字符只有三种情况,没坏,坏了但没被输出过,坏了但被输出过,所以不用bool,而用int
#include <iostream>
using namespace std;
const int N = 200;
int st[N]; // 1没坏,0坏了,2输出过
int main()
{
string s;
int k;
cin >> k >> s;
for (int i = 0; i < s.size(); i ++ )
{
int j = i + 1;
while (j < s.size() && s[j] == s[i]) j ++ ;
int len = j - 1 - i + 1;
if (len % k) st[s[i]] = 1;
i = j - 1; // 因为还要 ++
}
string res;
for (int i = 0; i < s.size(); i ++ )
{
if (!st[s[i]]) cout << s[i], st[s[i]] = 2;
if (st[s[i]] == 1) res += s[i];
else
{
res += s[i];
i += k - 1;
}
}
cout << endl << res << endl;
return 0;
}
1116 Come on! Let’s C (20 分)
- 题意 :按排名给id(1e4以内的正整数),根据询问的id判断是否在排名中出现过和是否被询问过,然后是排名第一和排名是否质数
- 思路 :先把10^4以内的质数先标记一下,用筛法求质数,O(nloglogn);先用过Rank[id]再标记为-1;Rank数组有三种状态,Rank==0代表没有出现过,Rank是-1代表输出过了,Rank是正整数代表正常排名且未输出;st数组有三种状态,0表示筛法时没有被筛过(未被染色)在10 ^4以内也就只有1,1表示是质数,2表示非质数
- 语法 :注意观察发现输出时必须%04d,像这种固定位数的编号题;
#include <iostream>
using namespace std;
const int N = 1e4 + 10;
int Rank[N], st[N];
void init()
{
for (int i = 2; i < N; i ++ )
if (!st[i])
{
st[i] = 1;
for (int j = i * 2; j < N; j += i)
st[j] = 2;
}
}
int main()
{
init();
int n;
cin >> n;
for (int i = 1; i <= n; i ++ )
{
int id;
cin >> id;
Rank[id] = i;
}
int k;
cin >> k;
while (k -- )
{
int id;
cin >> id;
printf("%04d: ", id);
if (!Rank[id]) puts("Are you kidding?");
else if (Rank[id] == -1) puts("Checked");
else
{
int t = st[Rank[id]];
if (!t) puts("Mystery Award");
else if (t == 1) puts("Minion");
else puts("Chocolate");
Rank[id] = -1;
}
}
return 0;
}
1152 Google Recruitment (20 分)
- 题意 :在给出的一个L(<=1000)位的数中找到第一个K(<10)位的质数
- 思路 :判断一个数是否是质数,这个题k最大是9位,就是 1 0 9 − 1 10^9-1 109−1,不可能把这之间所有质数都找出来,可以用试除法判断,既可以用自然数来试,也可以用质数来试,到 x 1 / 2 x^{1/2} x1/2,如果用自然数来试,最坏情况每次试 ( 1 0 9 ) 1 / 2 (10^9)^{1/2} (109)1/2,差不多3e4,最多1000位,所以3e7,有可能会超时,我们优化一下,试除法的时候不用自然数来试而是用质数来试;费马 :1到n中质数的个数大概是 n / ( l n n ) n/(lnn) n/(lnn),ln(3e4)肯定大于10,也就是可以比自然数效率高10倍以上;所以这道题就是先将1到 ( 1 0 9 ) 1 / 2 (10^9)^{1/2} (109)1/2以内的质数先筛出来,
- 语法 :这里是先筛质数而不是判断质数,所以1这个特殊情况就不用管了,因为我们只用到primes数组里的东西,st数组不在这题里用;循环条件中的primes[i]
#include <iostream>
using namespace std;
const int N = 4e4;
int primes[N], cnt;
bool st[N];
void init()
{
for (int i = 2; i < N; i ++ )
if (!st[i])
{
primes[cnt ++ ] = i;
for (int j = i * 2; j < N; j += i)
st[j] = true;
}
}
bool check(string s)
{
int x = stoi(s);
for (int i = 0; primes[i] <= x / primes[i]; i ++ )
if (x % primes[i] == 0)
return false;
return true;
}
int main()
{
init();
int l, k;
string s;
cin >> l >> k >> s;
for (int i = 0; i + k <= l; i ++ )
{
string ss = s.substr(i, k);
if (check(ss))
{
cout << ss;
return 0;
}
}
cout << 404;
return 0;
}
第八章、动态规划
1007 Maximum Subsequence Sum (25 分)
- 题意 :注意最后输出的不是索引而是在那个索引的数
- 思路 :f为当前的假设开始指针,每一次累加到sum,如果sum大于res,就更新res,开始指针和结束指针;如果sum小于0,说明这段都不要了,那么sum清零,f从下一位开始
#include <iostream>
using namespace std;
const int N = 1e4 + 10;
int num[N];
int main()
{
int n;
cin >> n;
for (int i = 0; i < n; i ++ ) cin >> num[i];
int res = -1e9, sum = 0, from = 0, to = 0, f = 0;
for (int i = 0; i < n; i ++ )
{
sum += num[i];
if (sum > res) res = sum, from = f, to = i;
if (sum < 0) sum = 0, f = i + 1;
}
if (res < 0) res = 0, from = 0, to = n - 1;
cout << res << ' ' << num[from] << ' ' << num[to];
return 0;
}
- 思路 :dp就是求很多集合中的最优解。状态表示为f[i],集合是所有以i为右端点的区间,属性是区间和的最大值,那么f[i]可以被分为两个区间,一个是区间长度为1,那么区间和的最大值就是w[i],一个是区间长度不为1,那么区间和的最大值就是f[i - 1] + w[i],所以 f [ i ] = m a x ( w [ i ] , f [ i − 1 ] + w [ i ] ) f[i]=max(w[i],f[i-1]+w[i]) f[i]=max(w[i],f[i−1]+w[i]),也就是 f [ i ] = w [ i ] + m a x ( 0 , f [ i − 1 ] ) f[i]=w[i]+max(0, f[i-1]) f[i]=w[i]+max(0,f[i−1]),由于这里f[i]只会用到f[i-1],就发现其实f数组不需要开,可以用一个变量来存
#include <iostream>
using namespace std;
const int N = 1e4 + 10;
int w[N];
int main()
{
int n;
cin >> n;
for (int i = 1; i <= n; i ++ ) cin >> w[i];
int res = -1, l, r;
for (int i = 1, sum = -1, start; i <= n; i ++ )
{
if (sum < 0) sum = 0, start = i;
sum += w[i];
if (sum > res)
{
res = sum;
l = w[start], r = w[i];
}
}
if (res < 0) res = 0, l = w[1], r = w[n];
cout << res << ' ' << l << ' ' << r;
return 0;
}
第九章、哈希表
1120 Friend Numbers (20 分)
- 思路 :什么数据结构可以让我们既判重又排序呢?其实不用哈希表而用set会更好,可以少一步排序
- 语法 :set默认从小到大排序;空格输出新方法(这题如果不判空格会wa)
#include <iostream>
#include <set>
using namespace std;
int main()
{
int n;
cin >> n;
set<int> se;
while (n -- )
{
int x;
cin >> x;
int s = 0;
while (x) s += x % 10, x /= 10;
se.insert(s);
}
cout << se.size() << endl;;
bool is_first = true;
for (auto x : se)
{
if (is_first) is_first = false;
else cout << ' ';
cout << x;
}
return 0;
}
1144 The Missing Number (20 分)
- 思路 :这里用while比用for方便,就是找一个从1开始连续增加的数字
- 语法 :set的insert和find均为 O ( l o g n ) O(logn) O(logn),count为 O ( k + l o g n ) O(k+logn) O(k+logn)
#include <iostream>
#include <unordered_set>
using namespace std;
int main()
{
int n;
cin >> n;
unordered_set<int> se;
while (n -- )
{
int x;
cin >> x;
se.insert(x);
}
int res = 1;
while (se.count(res)) res ++ ;
cout << res;
return 0;
}
第十章、并查集
第十一章、模拟
1008 Elevator (20 分)
- 思路 :last可能等于cur,而无论是否相等,res都是+5的
#include <iostream>
using namespace std;
int main()
{
int n;
cin >> n;
int res = 0, last = 0;
while (n -- )
{
int cur;
cin >> cur;
if (cur > last) res += 6 * (cur - last);
else res += 4 * (last - cur);
res += 5;
last = cur;
}
cout << res;
return 0;
}
1011 World Cup Betting (20 分)
- 思路 :三次,每次将输入的三个数中最大的的对应字母输出,最后再乘上最大的数
#include <iostream>
using namespace std;
int main()
{
double res = 1;
double w, t, l;
for (int i = 0; i < 3; i ++ )
{
cin >> w >> t >> l;
double x = max(w, max(t, l));
if (w == x) cout << "W ";
else if (t == x) cout << "T ";
else cout << "L ";
res *= x;
}
printf("%.2lf", (res * 0.65 - 1) * 2);
return 0;
}
1031 Hello World for U (20 分)
- 题意 :输出U型字符串,满足 n 1 = = n 3 , n 1 + n 2 + n 3 − 2 = = n n_1==n_3,n_1+n_2+n_3-2==n n1==n3,n1+n2+n3−2==n,且 n 1 n_1 n1和 n 2 n_2 n2尽可能近
- 思路 :根据等式,一个 n 1 n_1 n1一定对应 n 2 和 n 3 n_2和n_3 n2和n3,所以直接令 n 1 = ( n + 2 ) / 3 n_1=(n+2)/3 n1=(n+2)/3就是尽可能近的结果,那么得到了 n 1 , n 2 , n 3 n_1,n_2,n_3 n1,n2,n3;剩下的就是在一个矩阵中填入字符了,分为三个部分,注意第三个部分是从下往上填的;输出矩阵时,如果 g [ i ] [ j ] = = 0 g[i][j] ==0 g[i][j]==0,说明没有在这个位置填过(注意不是字符0),就输出空格。
- 语法 :字符矩阵中没有被填过的部分如何表示。
#include <iostream>
using namespace std;
char g[85][85];
int main()
{
string str;
cin >> str;
int n = str.size();
int n1 = (n + 2) / 3;
int n3 = n1, n2 = n - n1 - n3 + 2;
int k = 0;
for (int i = 0; i < n1; i ++ ) g[i][0] = str[k ++ ];
for (int i = 1; i <= n2 - 2; i ++ ) g[n1 - 1][i] = str[k ++ ];
for (int i = n1 - 1; i >= 0; i -- ) g[i][n2 - 1] = str[k ++ ];
for (int i = 0; i < n1; i ++ )
{
for (int j = 0; j < n2; j ++ )
if (g[i][j]) cout << g[i][j];
else cout << ' ';
cout << endl;
}
return 0;
}
1041 Be Unique (20 分)
- 题意 :找到输入的数中第一个只出现过一次的数
- 思路 :先用一维数组存下按顺序输入的数,再套一个一维数组存数对应出现的次数,那么遍历第一个数组首先找到次数为1的数就可以直接break了
#include <iostream>
using namespace std;
const int N = 1e5 + 10;
int a[N], c[N];
int main()
{
int n;
cin >> n;
for (int i = 0; i < n; i ++ )
{
cin >> a[i];
c[a[i]] ++ ;
}
for (int i = 0; i < n; i ++ )
if (c[a[i]] == 1)
{
cout << a[i];
return 0;
}
puts("None");
return 0;
}
1042 Shuffling Machine (20 分)
- 思路 :牌号的规律,先不管字母,就是1-54号的牌,然后再根据函数对应打印;最后结果要按照位序打印出对应位序上的数,所以想到用一个一维数组记录当前位序i对应的数,因为要经过k次洗牌,且不能覆盖当前的,想到再开一个一维数组记录上一次位序i对应的数。
- 语法 :memcpy函数在cstring头文件中
#include <iostream>
#include <cstring>
using namespace std;
const int N = 60;
int p[N], q[N], w[N];
void print(int x)
{
if (x <= 13) cout << 'S' << x;
else if (x <= 26) cout << 'H' << x - 13;
else if (x <= 39) cout << 'C' << x - 26;
else if (x <= 52) cout << 'D' << x - 39;
else cout << 'J' << x - 52;
}
int main()
{
int k;
cin >> k;
for (int i = 1; i <= 54; i ++ ) cin >> q[i];
for (int i = 1; i <= 54; i ++ ) p[i] = i;
while (k -- )
{
memcpy(w, p, sizeof p);
for (int i = 1; i <= 54; i ++ ) p[q[i]] = w[i];
}
for (int i = 1; i <= 54; i ++ )
{
print(p[i]);
if (i != 54) cout << ' ';
}
}
1054 The Dominant Color (20 分)
- 题意 :找到n * m的矩阵中出现次数超过n * m / 2的并输出,直接模拟即可。
#include <iostream>
#include <unordered_map>
using namespace std;
int main()
{
int n, m;
cin >> m >> n;
unordered_map<int, int> cnt;
for (int i = 0; i < n; i ++ )
for (int j = 0; j < m; j ++ )
{
int x;
cin >> x;
if ( ++ cnt[x] > n * m / 2)
{
cout << x;
break;
}
}
return 0;
}
1065 A+B and C (64bit) (20 分)
- 思路 :考察C++中整数在计算机中表示的方法;数据范围是所有的long long范围,所以ab相加可能会溢出,而溢出情况只可能有两种,一正一负不可能溢出,不溢出直接运算就可以;如果是第一种情况的溢出,由于C是范围内的数,所以一定大于c,第二种情况则反之
- 最高位是0是非负数,是1是负数;表示负数就是正数所有位取反再加一(~x+1);大于等于0的范围是 0 到 2 63 − 1 0到2^{63}-1 0到263−1,负数是 − 2 63 到 − 1 -2^{63}到-1 −263到−1;所以两个正数相加溢出的范围是 2 63 到 2 64 − 2 2^{63}到2^{64}-2 263到264−2,那么最高位一定是1,所以两个正数相加溢出一定变成负数。
- 语法 :long long 对应%lld
#include <iostream>
using namespace std;
typedef long long LL;
bool check(LL a, LL b, LL c)
{
LL d = a + b;
if (a >= 0 && b >= 0 && d < 0) return true;
if (a < 0 && b < 0 && d >= 0) return false;
return a + b > c;
}
int main()
{
int n;
cin >> n;
for (int i = 1; i <= n; i ++ )
{
LL a, b, c;
scanf("%lld%lld%lld", &a, &b, &c);
if (check(a, b, c)) printf("Case #%d: true\n", i);
else printf("Case #%d: false\n", i);
}
return 0;
}
1069 The Black Hole of Numbers (20 分)
- 题意 :直到得到结果是0或者6174才停下,这个时候的式子也是要输出的;注意这道题分别获得两个数的时候无论原来的数是几位,后来都是获得两个四位数,也就是四次*10
- 语法 :sort默认从小到大;函数可以返回vector容器;sort在algorithm头文件中; r e v e r s e reverse reverse在algorithm头文件中;dowhile。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
vector<int> get(int n)
{
int nums[4];
for (int i = 0; i < 4; i ++ )
{
nums[i] = n % 10;
n /= 10;
}
sort(nums, nums + 4);
int a = 0;
for (int i = 0; i < 4; i ++ ) a = a * 10 + nums[i];
reverse(nums, nums + 4);
int b = 0;
for (int i = 0; i < 4; i ++ ) b = b * 10 + nums[i];
return {b, a};
}
int main()
{
int n;
cin >> n;
do
{
auto t = get(n);
printf("%04d - %04d = %04d\n", t[0], t[1], t[0] - t[1]);
n = t[0] - t[1];
} while (n && n != 6174);
return 0;
}
1092 To Buy or Not to Buy (20 分)
- 思路 :多多少和少多少相互之间是没有影响的,如果少多少是0才输出多多少
- 语法 :unordered_map的遍历
#include <iostream>
#include <unordered_map>
using namespace std;
int main()
{
string a, b;
cin >> a >> b;
unordered_map<char, int> S;
for (auto c : a) S[c] ++ ;
for (auto c : b) S[c] -- ;
int sp = 0, sn = 0;
for (auto item : S)
if (item.second > 0) sp += item.second;
else sn -= item.second;
if (sn) printf("No %d", sn);
else printf("Yes %d", sp);
return 0;
}
1128 N Queens Puzzle (20 分)
- 题意 :diagonal对角线
- 语法 :一组样例多组输入的题目不要随意break!!利用数组的坐标系去看的话,也就是->y,|V为x,得知反对角线是y-x是个定值(y=x+b,与寻常坐标系反),而正对角线是y+x是个定值
#include <iostream>
#include <cstring>
using namespace std;
const int N = 1e3 + 10;
bool row[N], dg[N * 2], udg[N * 2];
int main()
{
int T;
cin >> T;
while (T -- )
{
memset(row, 0, sizeof row);
memset(dg, 0, sizeof dg);
memset(udg, 0, sizeof udg);
int n;
cin >> n;
bool success = true;
for (int y = 1; y <= n; y ++ )
{
int x;
cin >> x;
if (row[x] || dg[y + x] || udg[y - x + n]) success = false;
row[x] = dg[y + x] = udg[y - x + n] = true;
}
if (success) puts("YES");
else puts("NO");
}
return 0;
}
1132 Cut Integer (20 分)
- 语法 :当将任何变量放在“/‘后面或者”%“后面都要注意它是否为0
#include <iostream>
using namespace std;
int main()
{
int T;
cin >> T;
while (T -- )
{
string s;
cin >> s;
int len = s.size() / 2;
int left = stoi(s.substr(0, len));
int right = stoi(s.substr(len, len));
int n = stoi(s);
if (left * right && n % (left * right) == 0) puts("Yes");
else puts("No");
}
return 0;
}
1140 Look-and-say Sequence (20 分)
- 思路 :问的是序列中第n个数,所以循环的是n-1次;找字符串中连续的次数的方法
#include <iostream>
using namespace std;
int main()
{
int d, n;
cin >> d >> n;
string cur = to_string(d);
for (int k = 0; k < n - 1; k ++ )
{
string next;
for (int i = 0; i < cur.size();)
{
int j = i + 1;
while (j < cur.size() && cur[i] == cur[j]) j ++ ;
next += cur[i] + to_string(j - i);
i = j;
}
cur = next;
}
cout << cur;
return 0;
}
第十二章、贪心
第十三章、链表
第十四章、基础算法与数据结构
1046 Shortest Distance (20 分)
- 思路 :前缀和
- 语法 : s w a p 和 m i n 和 m a x swap和min和max swap和min和max只需要 i o s t r e a m iostream iostream头文件;while里面如果要使得结尾无空行,判断条件是m!=0而不是m!=1
#include <iostream>
using namespace std;
const int N = 1e5 + 10;
int s[N];
int main()
{
int n;
cin >> n;
for (int i = 1; i <= n; i ++ ) cin >> s[i], s[i] += s[i - 1];
int m;
cin >> m;
while (m -- )
{
int l, r;
cin >> l >> r;
if (r < l) swap(l, r);
cout << min(s[r - 1] - s[l - 1], s[n] - s[r - 1] + s[l - 1]);
if (m != 0) cout << endl;
}
}
1148 Werewolf - Simple Version (20 分)
- 题意 :in ascending order 升序
- 思路 :以两个狼人为假设(枚举时j为i+1,不重不漏),如果谎话数不是1就no,然后再统计总的谎话数如果不是2就no;谎话数的判断,传入第几个人以及两个狼人分别是谁这三个参数,如果这个人判断的是人类,…,如果判断的是狼人…。
#include <iostream>
using namespace std;
const int N = 110;
int q[N];
int judge(int k, int i, int j) // 1为假话,0为真话
{
int t = q[k];
if (t > 0)
{
if (t == i || t == j)
return 1;
return 0;
}
t = -t;
if (t == i || t == j) return 0;
return 1;
}
int main()
{
int n;
cin >> n;
for (int i = 1; i <= n; i ++ ) cin >> q[i];
for (int i = 1; i <= n; i ++ )
for (int j = i + 1; j <= n; j ++ )
{
int s = 0;
s = judge(i, i, j) + judge(j, i, j);
if (s != 1) continue;
s = 0;
for (int k = 1; k <= n; k ++ )
s += judge(k, i, j);
if (s != 2) continue;
cout << i << ' ' << j;
return 0;
}
cout << "No Solution";
return 0;
}