1824 字
9 分钟
L1-006~L1-010的笔记
Waiting for api.github.com...
P.S. 这份笔记同步发布在我的博客上,建议在博客中查看以享受完整的MD Extended Features. 你可以点此快速跳转到相应页面,我的博客地址为https://samera2022.github.io
L1-006
代码部分
#include <bits/stdc++.h>using namespace std;typedef long long ll;//Spec A 2/20 Point
void solve(int N);
int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); int N; cin>>N; solve(N); return 0;}
void solve(const int N) { //Spec Tip Start int crtMax = 1;//连续因数的个数的最大值 int crt = N;//连续因数最小值,当其为质数时即为其本身 //Spec Tip End for (int i = 2; i<=sqrt(N); i++) { if (int n = N; n%i==0) { int delta = 0; bool valid = n%(i+delta)==0; while (valid) { n/=i+delta; valid = n%(i+delta+1)==0; if (valid) delta++; else break; } //Spec Tip Start //delta+1代表此时的连续因数长度,此时有更长连续因数长度时,对crt进行同步 if (delta+1>crtMax) { crtMax = delta+1; crt = i; } if (crt==N) crt = i;//需要最小因子序列,因此需要考虑其可分解为两数相乘时,连续因数最小值改为最小因数 //Spec Tip End } } cout<<crtMax<<"\n"; for (int i = 0; i < crtMax; i++) { cout<<crt+i; if (i!=crtMax-1) cout<<"*"; }}笔记部分
- 没有什么好记的,这题主要是算法上稍微绕了一下。
L1-007
代码部分
#include <bits/stdc++.h>using namespace std;typedef long long ll;
void solve(const string& s);
int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); string s; cin>>s; solve(s); return 0;}
void solve(const string& s) { string result; int len = static_cast<int>(s.length()); for (int i = 0; i<len; i++) { switch (s[i]) { case '-': result.append("fu"); break; case '1': result.append("yi"); break; case '2': result.append("er"); break; case '3': result.append("san"); break; case '4': result.append("si"); break; case '5': result.append("wu"); break; case '6': result.append("liu"); break; case '7': result.append("qi"); break; case '8': result.append("ba"); break; case '9': result.append("jiu"); break; case '0': result.append("ling"); break; default: break; } if (i!=len-1) result.append(" "); } cout<<result;}笔记部分
- 此处用到了C++风格的强制转型
static_cast<int>(),Java中的写法(int)也能用,但是那被称为C风格的强制转型。 - C++中的
string可以像Java的StringBuilder一样使用append方法。更进一步地,C++的字符串可以直接编辑原处,而Java的字符串由于其不可变导致只能编辑副本,这使得C++的字符串更轻一些。 - 也许有人会说为啥我写这么长的
switch-case都不考虑直接单独处理符号再写个数组来处理0~9,究其根本, 我只能说我想试试C++中的switch-case和Java中是否一致))
L1-008
代码部分
#include <bits/stdc++.h>using namespace std;typedef long long ll;//Spec A 2/10 Point
void solve(int A, int B);void handle(int num);
int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); int A; cin>>A; int B; cin>>B; solve(A,B); return 0;}
void solve(const int A, const int B) { const int total = B - A + 1; const int time = total / 5; for (int i = 1; i <= time; i++) { for (int j = 1; j<=5; j++) handle(A+5*(i-1)+(j-1)); cout<<"\n"; } //Spec Tip Start if (const int rest = total % 5; rest!=0) { for (int j = rest - 1; j >= 0; j--) handle(B-j); cout<<"\n"; } //Spec Tip End cout<<"Sum = "<<((A+B)*total/2);}
void handle(const int num) { string s = to_string(num); const int len = static_cast<int>(s.length()); const int lLen = 5 - len; for (int i = 1; i <= lLen; i++) cout<<" "; cout<<s;}笔记部分
- 此处的
solve方法直接采用了值传递。我们可以发现,值传递时,方法参数的const与否不妨碍其声明中无需写const。声明中的引用传递的const主要是为了确保方法不会修改原来的值,而值传递的情况下修改后和原来也无所谓,所以声明中不能再写const修饰。
L1-009
代码部分
#include <bits/stdc++.h>using namespace std;typedef long long ll;//Spec A 11/20 Point
pair<ll, ll> split(const string& s, char delimiter);ll gcd(ll a, ll b);void simplify(ll& a, ll& b);
int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); int N; cin>>N; ll curtNum = 0; ll curtDen = 1; for (ll i = 1; i <= N; i++) { string content; cin>>content; const auto [Num, Den] = split(content,'/'); curtNum = curtNum*Den+curtDen*Num; curtDen *= Den; simplify(curtNum, curtDen); } const ll res = curtNum/curtDen; ll resNum = curtNum%curtDen; simplify(resNum,curtDen); if (res==0&&resNum!=0) cout<<resNum<<"/"<<curtDen; if (res!=0&&resNum==0) cout<<res; if (res!=0&&resNum!=0) cout<<res<<" "<<resNum<<"/"<<curtDen; if (res==0&&resNum==0) cout<<0; return 0;}
pair<ll,ll> split(const string& s, const char delimiter) { pair<ll,ll> tokens; if (s.find(string(1,delimiter))!=string::npos) { string token; stringstream ss(s); getline(ss,token, delimiter); tokens.first = stoll(token); getline(ss, token, delimiter); tokens.second = stoll(token); } else { tokens.first = stoll(s); tokens.second = 1; } return tokens;}
ll gcd(ll a, ll b) { while (b != 0) { a %= b; swap(a, b); } return a;}
void simplify(ll& a, ll& b) { const ll multiplier = gcd(a,b); a /= multiplier; b /= multiplier;}笔记部分
- 我原来写的是先乘出完整的分母,再算出完整的分子,最后直接约分得到结果,但是这题有个小分值的测试点会超
long long的范围,导致只能逐步约分了。 - 也许有人会说为什么我要连着写四个
if而不用if else-if else,再或者在每个if的结构体中直接return 0;。究其根本,我只能说这是对称美)))言归正传,这确实会损失少量性能,不过我还是觉得这很美观)) - 本题中可能出现负数,在实际操作中求最大公约数(
gcd)是可以正常处理负数的,但是返回的结果可能需要进一步的操作。因而我直接采用了绝对值计算,这会保险一些。 - 另记:有人可能会采用递归写法的
gcd,需要补充的是,在递归深度达到1e5或1e6时,递归可能导致栈溢出(Stack Overflow),而循环则不会出现这种问题。此外,递归涉及调用、压栈、弹栈、参数传递等CPU操作,这也使得其常数时间通常比循环要大。 - C++中没有现成的
split方法,需要你手动进行实现……因此,我们需要清楚getline()的具体作用:首先需要指出的是,这是getline()函数的其中一个作用,另外一个作用等到下一次见到它的时候再说。该函数有三个参数,此处我们填入的是(stringstream, string, char)。getline首先会清空string中原有的内容,而后从stringstream中逐个读取字符,一直读取到char出现时停止读取,此时会将读取到的char之前的字符串存入你提供的string中。如果不填入char,则其会默认读到行末换行(不包含换行符)。由于内容会被存入string,这使得你只能传入左值(L-Value)进去。在这种情况下,getline起到的实际上是字符分割的作用。 - 另记:左值(
L-Value)是一个正常的变量,你可以通过变量名来访问它。右值(R-Value)是一个临时变量,你无法通过变量名来访问它(因为它不存在变量名)。比方说,to_string(num)是一个匿名返回值,你无法用一个变量名来访问它;"42"是一个字面量,你也无法用一个变量名来访问它。这些变量在所在行结束后就会被销毁,因而被算作右值(R-Value)。简单地说,你可以通过“是否有一个变量名”来快速判断左右值。
L1-010
代码部分
#include <bits/stdc++.h>using namespace std;typedef long long ll;
int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); int A,B,C = 0; cin>>A; cin>>B; cin>>C; vector v = {A,B,C}; sort(v.begin(), v.end()); for (int i = 1; i <= 3; i++) { cout<<v[i-1]; if (i!=3) cout<<"->"; } return 0;}笔记部分
- 一个比大小的题目,可以用
if-else来判断得到排序结果。这里我懒了一下,直接用数组排序了。 - C++的
vector和Java的ArrayList性质相似,但是在查询元素位置的时候,如果你使用vector.at(i),其会因为越界检查而比vector[i]要更慢。
L1-006~L1-010的笔记
https://samera2022.github.io/posts/Notes/GPLT/l1-006l1-010/