1.158同余方程
思路
纯数学的思路,想不出来的话很难做。
欧几里得算法视频讲解
代码
#include <iostream>
using namespace std;
// 扩展欧几里得:计算 ax + by = gcd(a, b) 的解
long long extended_gcd(long long a, long long b, long long &x, long long &y) {
if (b == 0) {
x = 1;
y = 0;
return a;
}
long long x1, y1;
long long gcd = extended_gcd(b, a % b, x1, y1);
x = y1;
y = x1 - (a / b) * y1;
return gcd;
}
int main() {
long long a, b;
cin >> a >> b;
long long x, y;
long long gcd = extended_gcd(a, b, x, y);
// 由于我们只需要模 b 的正整数解,所以我们要保证 x 是正数
x = (x % b + b) % b;
cout << x << endl;
return 0;
}
2.159大整数乘法
思路
从低到高按位相乘进位累加。
具体实现
1.先对其进行输入,分配给s1和s2分别代表两个大数,长度分别为n1和n2
2.由简单的数学知识可得n1*n2的数相乘的范围在(n1+n2-1,n1+n2),所以生成一个n1+n2全为'0'的字符串来存放相乘后的结果。
3.遍历,从右到左进行遍历(在代码中为了统一,我使用的是从左到右遍历,i,j,k分别代表与对应的最右端的距离来实现从右到左)
注意事项:这个里面只遍历n1+n2-1位,最高位是不进行遍历的,而是最后根据进位来进行计算的。
4遍历的内部逻辑:i,j分别代表相应的位数,根据数学知识可以知道(百位 = 百位*个位 + 十位*十位 + 个位*百位),所以第k位的值我们可以从s1[i]和s2[j]相乘获取。在这个里面,0代表个位,1代表十位等。所以k = i + j;
add表示进位,sum代表相应的累加和。得到乘法的结果之类,根据累加和得到对应的进位,然后sum只保留个位作为最后的当前位的值。
注意事项:要将'0'变成0才能参与相乘。先更新进位再更新累加和。
5.每次遍历前需要将sum = sum +add来获取当前位的累加值。同时将add = 0表示遍历前的进位为0,在遍历结束之后将sum = 0。
6.对最高位的处理,根据前面的进位来得到最高位,同时如果最高位最后的结果为0的话,要删除。
代码
#include<iostream>
#include<string>
using namespace std;
int main(){
string s,s1,s2;
getline(cin,s);
int i = 0;
int j = 0;
int n = s.size();
for(;i<n;i++){
if(s[i] == ' '){
s1 = s.substr(0,i);
break;
}
}
int n1 = i;//代表两个的长度
int n2 = n-i-1;
s2 = s.substr(i+1,n - i - 1);//获得对应的两个数
//cout<<n1<<" "<<n2<<endl;
string ret = string(n-1,'0');//最长的长度为这个,后序把0给消掉
int add = 0;//代表的是进位
int sum = 0;//代表的是累加和
for(int k = 0;k<n-2;k++){//最高位是不参与计算的,直接算最后的进位即可
sum = sum + add;//前面的进位
add = 0;//此时计算的就是当前位的进位了
for(i = 0;i<n1&&i<=k;i++){//满足两个情况1:长度在这个之内,2,位数要满足
j = k - i;//代表s2对应的位数
if(j>=n2){
continue;
}
int multi = (s1[n1-1-i]-'0')*(s2[n2-1-j]-'0');
//cout<<multi<<endl;
sum = sum + multi;
add += sum/10;
sum = sum%10;
}
ret[n-2-k] = sum + '0';
//cout<<n-2-k<<" "<<ret[n-2-k]<<endl;
sum = 0;//所有进位结束之后对应的累加和变为下一位,累加和设置为0
}
//再将最高位设置为进位
ret[0] = add + '0';//最高位为进位
//cout<<ret<<endl;
if(ret[0] == '0'){
ret.erase(0,1);//删除最高位
}
cout<<ret;
return 0;
}
3.160二维平面上的折线段
思路
计算当前值和需要到达的结点的距离分两种情况
1.距离大于s,此时更新位置并将此时的位置写入
2.距离小于s,此时更新位置和长度,同时指向的结点更新。
具体实现
len:代表的是还需要移动的距离。
diff:代表的是当前位置与结点的距离。
注意事项:需要使用#include<iomanip>来控制输出的精度。
代码
#include<iostream>
#include<vector>
#include<cmath>
#include<iomanip>
using namespace std;
int main(){
int N;
cin>>N;
vector<vector<double>> mp(N,vector<double>(2,0));
for(int i = 0;i<N;i++){
cin>>mp[i][0]>>mp[i][1];
}
double s;
cin>>s;
double len = s;//代表剩余的长度
vector<vector<double>> ret;
ret.push_back(mp[0]);
int i = 1;
vector<double> cur = mp[0];
double sz = 0;
while(i<N){//代表在这个范围之内
double diff = sqrt((mp[i][0]-cur[0])*(mp[i][0]-cur[0]) + (mp[i][1]-cur[1])*(mp[i][1]-cur[1]));
//cout<<diff<<" "<<len<<endl;
if(diff >= len){
sz = len/diff;
cur[0] = cur[0] + sz * (mp[i][0]-cur[0]);
cur[1] = cur[1] + sz * (mp[i][1]-cur[1]);
ret.push_back(cur);
len = s;//此时长度重新回到了原来的长度
}else{
len = len - diff;//还需要操作的距离
cur = mp[i];
i++;
}
}
int n= ret.size();
std::cout << std::fixed << std::setprecision(5);
for(int i = 0;i<n;i++){
cout<<ret[i][0]<<", "<<ret[i][1]<<endl;
}
return 0;
}