1.取消同步
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
2.素数判断模板--简单方法、埃氏筛、欧拉筛
2.1简单方法
bool is_prime(int x)
{
if(x==1) return false;
if(x==2) return true;
else
{
for(int i = 2;i*i <= x;i++)
if(x%i==0) return false;
return true;
}
}
2.2埃氏筛
利用质因子进行,筛掉2,3,5,7...的倍数
const int N = 1e8;
bool is_prime[N+1];
for(int i = 2;i <= sqrt(n);i++)
{
if(is_prime[i]==0)//代表是素数
{
for(int j = i*i;j <= n;j+=i)
{
is_prime[j] = 1;//不是素数
}
}
}
2.3欧拉筛(比埃氏筛高效)
确保每个合数只被最小质因数筛掉,每个合数不会重复被筛去
const int N = 1e7;
int prime[N+1];
bool visit[N+1];
memset(visit,0,sizeof visit);
memset(prime,0,sizeof prime);
int cnt = 0;
for(int i = 2;i <= n;i++)
{
if(!visit[i])
{
prime[cnt++] = i;
}
for(int j = 0;j < cnt;j++)
{
if(i * prime[j] > n) break;
visit[i * prime[j]] = 1;
if(i % prime[j]==0) break;
}
}
3.字符串排序
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
string s[100];
int main()
{
int n;
cin>>n;
for(int i = 0;i < n;i++)
cin>>s[i];
sort(s,s+n);
for(int i = 0;i < n;i++)
cout<<s[i];
return 0;
}
//假如有三个字符串abc,bef,bcd,排序后就是abc,bcd,bef
4.排序函数sqrt,sqrtl,sqrtf
sqrt()函数--适用于双精度数据,返回double类型
sqrtf()函数--适用于浮点型数据,返回float类型
sqrtl()函数--适用于长双进度类型,返回long double类型
5.优先队列--实现自动排序
从小到大:priority_queue<int,vector<int>,greater<int> >q;
从大到小:priority_queue<int>q;
优先队列每次讲优先级最高的元素先出队列
题目讲解:https://www.luogu.com.cn/problem/P2085
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
priority_queue< int,vector<int>,greater<int> >q;
int n,m;
long long sum(int a,int b,int c)//(f(x) = ax^2+bx+c)
{
for(int i = 1;i <= 100;i++)
{
long long sum;
sum = a * i * i + b * i + c;
q.push(sum);
}
}
int main()
{
cin>>n>>m;
while(n--){
int a,b,c;
cin>>a>>b>>c;
sum(a,b,c);
}
while(m--){
cout<<q.top()<<" ";
q.pop();
}
return 0;
}
6.字符串与数字的转换
字符串转化为数字:
int num = stoi(str);(转化为int)
int num = stol(str);(转化为long)
int num = stoll(str);(转化为longlong)
数字转化为字符串:
string str = to_string(num);
7.快速幂与矩阵快速幂
7.1快速幂
假设我们需要计算2^25次方,按照传统的方法需要计算25次,而对于快速幂算法只需要计算三次
25=1+8+16 | 00011001 |
1 | 00000001 |
8 | 00001000 |
16 | 00010000 |
long long fastpow(long long a,long long n,long long m)
{
if(n == 0) return 1;
if(n == 1) return a;
long long temp = fastpow(a,n/2,m);
if(n%2 == 1) return temp * temp * a % m;//奇数
else return temp * temp % m;//偶数
}
7.2矩阵快速幂
题目:https://www.luogu.com.cn/problem/P3390
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
const int N = 110;
const int mod = 1e9+7;
long long n,k;
struct matrix
{
long long m[N][N];//使用二维数组存储矩阵
};
matrix operator * (const matrix& a,const matrix& b)//重载乘法运算符以支持矩阵乘法
{
matrix c;
memset(c.m,0,sizeof(c.m));//初始化c矩阵
for(int i = 0;i < N;i++)
{
for(int j = 0;j < N;j++)
{
for(int k = 0;k < N;k++)
{
c.m[i][j] = (c.m[i][j] + a.m[i][k]*b.m[k][j])%mod;
}
}
}
return c;
}
//* 外层循环变量`i`遍历结果矩阵`c`的行。
//* 中层循环变量`j`遍历结果矩阵`c`的列。
//* 内层循环变量`k`是中间变量,用于计算`a`的第`i`行和`b`的第`j`列的点积,即矩阵乘法的核心步骤。
//* 在每次内层循环中,我们都将`a`的第`i`行第`k`列的元素与`b`的第`k`行第`j`列的元素相乘并将结果
//加到`c`的第`i`行第`j`列的元素上。注意,这里还使用了模数`mod`进行取模操作,以避免整数溢出。
int main()
{
cin>>n>>k;
matrix A;
for(int i = 0;i < n;i++)
{
for(int j = 0;j < n;j++)
{
cin>>A.m[i][j];
}
}
matrix ans;
memset(ans.m,0,sizeof(ans.m));
for(int i = 0;i < n;i++)
{
ans.m[i][i] = 1;
}
while(k)
{
if(k&1)//奇数
{
ans = ans * A;
}
A = A * A;
k>>=1;
}
for(int i = 0;i < n;i++)
{
for(int j = 0;j < n;j++)
{
cout<<ans.m[i][j]<<" ";
}
cout<<endl;
}
return 0;
}
8.阶乘之和1! + 2! + 3! + ... + n!
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1010;
int a[maxn],res[maxn];//a 被用来计算 i!,而 res 被用来存储所有阶乘的和。
int main()
{
int n;
cin>>n;
a[0] = 1;//阶乘从1开始,所以 a[0] 初始化为1(代表1!),
res[0] = 1;//res[0] 也初始化为1(代表1!的和)
for(int i = 2;i <= n;i++)
{
int carry = 0;//判断进位
for(int j = 0;j < maxn;j++)
{
a[j] = carry + a[j] * i;
carry = a[j]/10;
a[j]%=10;
}
//计算i的阶乘
for(int j = 0;j < maxn;j++)
{
res[j] += a[j];
res[j+1] += res[j]/10;
res[j]%=10;
}
//将结果加到res中
}
int len = maxn;
while(res[len-1]==0&&len>1)//去除前导0
{
len--;
}
for(int i = len-1;i >= 0;i--)//逆序输出
{
cout<<res[i];
}
return 0;
}
9.进制转换
printf("%05o\n",35); //按八进制格式输出,保留5位高位补零
printf("%03d\n",35); //按十进制格式输出,保留3位高位补零
printf("%05x\n",35); //按十六进制格式输出,保留5位高位补零
9.1任意2-36进制数转化为10进制数
int Atoi(string s,int radix) //s是给定的radix进制字符串
{
int ans=0;
for(int i=0;i<s.size();i++)
{
char t=s[i];
if(t>='0'&&t<='9') ans=ans*radix+t-'0';//这个数小于10
else ans=ans*radix+t-'A'+10;//这个是大于等于A
}
return ans;
}
9.2将10进制数转换为任意的n进制数,结果为char型
string decimalToBase(int decimal, int base) {
string digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
string result = "";
while (decimal > 0) {
result = digits[decimal % base] + result;
decimal /= base;
}
return result.empty() ? "0" : result;
}
9.3利用函数
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n;
cin>>n;
cout<<n<<"的八进制为:"<<oct<<n<<endl;
cout<<n<<"的十进制为:"<<dec<<n<<endl;
cout<<n<<"的十六进制为:"<<hex<<n<<endl;
cout<<n<<"的二进制为:"<<bitset<8>(n)<<endl;
return 0;
}
10.辗转相除法与最小公倍数
辗转相除法:最大公因数
int gcd(int a int b)
{
return b?gcd(b,a%b):a;
}
//或者直接利用函数 __gcd(a,b)
最小公倍数
int lcm(int a,int b)
{
return a/gcd(a,b)*b;
}
11.高精度加减乘除
11.1高精度加法
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
string s1,s2; //将所需要计算的数字以字符串的形式进行输入
int len1,len2,len; //标记字符串的长度
int a[10005],b[10005]; //将字符串的每一位转化为数字,即将字符串转换为数字
int main()
{
cin>>s1>>s2;
len1 = s1.size(),len2 = s2.size();
len = max(len1,len2);//选出更大的数的长度,再进行运算
for(int i = 0;i < len1;i++)
{
a[i] = s1[len1 - i- 1] - '0'; //转化为数字
}
for(int i = 0;i < len2;i++)
{
b[i] = s2[len2 - i - 1] - '0';
}
for(int i = 0;i < len;i++)
{
a[i] = a[i] + b[i]; //将a[i] + b[i]的值赋值给a[i];
a[i+1] = a[i+1] + a[i]/10; //a[i+1]的值为当前的值加上进位的数,进位的数等于a[i]/10;
a[i] %= 10; //取余,每个数不超过10,前面已经将进位的数加上去了,直接取余就是结果
}
if(a[len]!=0&&len>0) //a[len]!=0代表超出当前的位数,比如三位数加三位数可能为四位数,
//此时长度加1,最多也就加1,因为三位数加三位数不会为五位数
{
len++;
}
for(int i = len-1;i >= 0;i--)
{
cout<<a[i];
}
//逆序输出结果
return 0;
}
11.2高精度减法
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
string s1,s2;
int a[10005],b[10005],c[10005]; //用c数组来存储结果
int len1,len2,len;
int flag = 0; //用来标记是否需要负号
bool compare(string s1,string s2) //两个字符串进行大小比较
{
int len1 = s1.size(),len2 = s2.size();
if(len1!=len2) //两个字符串不相等
{
if(len1>len2) //s1>s2就return true
return true;
else
return false;
}
//两个字符串相等
for(int i = 0;i < len1;i++)
{
if(s1[i]!=s2[i])
{
if(s1[i] > s2[i]) //s1>s2就return true
return true;
else
return false;
}
}
return true; //两个字符串完全相等
}
int main()
{
cin>>s1>>s2;
if(!compare(s1,s2))//s2>s1
{
flag = 1; //负号
s1.swap(s2); //将两个字符串交换
}
len1 = s1.size(),len2 = s2.size();
len = max(len1,len2); //选出那个较长的字符串
for(int i = 0;i < len1;i++)
{
a[i] = s1[len1-i-1] - '0'; //将字符转换为数字
}
for(int i = 0;i < len2;i++)
{
b[i] = s2[len2-i-1] - '0';
}
for(int i = 0;i < len;i++)
{
if(a[i] < b[i]) //借位运算
{
a[i+1]--;
a[i] = a[i] + 10;
}
c[i] = a[i] - b[i];
}
while(c[len-1]==0&&len>1) //去除前导0
{
len--;
}
if(flag==1) //flag==1输出负号
{
cout<<"-";
}
for(int i = len-1;i >= 0;i--)
{
cout<<c[i]; //逆序输出结果
}
return 0;
}
11.3高精度乘法
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
string s1,s2;
int a[10005],b[10005],c[10005];
int len1,len2,len;
int main()
{
cin>>s1>>s2;
len1 = s1.size(),len2 = s2.size();
len = len1 + len2;//两个数相乘结果最长为len1+len2,如两位数与两位数相乘最大结果为四位数
for(int i = 0;i < len1;i++)
{
a[i] = s1[len1-1-i] - '0';
}
for(int i = 0;i < len2;i++)
{
b[i] = s2[len2-1-i] - '0';
}
for(int i = 0;i < len1;i++)
{
for(int j = 0;j < len2;j++)
{
c[i+j] += a[i] * b[j];
}
}
int x = 0;
for(int i = 0;i < len;i++)
{
c[i] += x;
x = c[i]/10;
c[i] %= 10;
}
while(c[len-1]==0&&len>1)
{
len--;
}
for(int i = len-1;i>=0;i--)
{
cout<<c[i];
}
return 0;
}
11.4高精度除法
高精度/低精度
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
string s1;
long long b;
long long a[10005],c[10005];
long long len;
long long d = 0;
int main()
{
cin>>s1;
cin>>b;
len = s1.size();
for(int i = 0;i < len;i++)
{
a[i] = s1[len-1-i] - '0';
}
for(int i = len-1;i >= 0;i--)
{
d = d*10 + a[i];
c[i] = d / b;
d %= b;
}
while(c[len]==0&&len>0)
{
len--;
}
for(int i = len;i >= 0;i--)
{
cout<<c[i];
}
return 0;
}
高精/高精
#include <stdio.h>
#include<string.h>
char arra[20000] = { 0 }, arrb[20000] = { 0 };//分别储存a,b的值
int ans[20000] = { 0 };//储存商
int judge(char* arr1, char* arr2, int len)//判断是否可以相减的函数
{
if (arr1[len] >'0') return 1; //如果arr1比arr2长, 则可以除
for (int i = len - 1; i >= 0; i--) {//从arr的最高位开始与arr2比较
if (arr1[i] > arr2[i]) return 1;//相同位时arr1中的数字更大,则可以相除
else if (arr1[i] < arr2[i]) return 0;//相同位时arr1数字更小则不能相除
}
return 1;//arr1和arr2完全一样,可以相除
}
void my_reverse(char* arr, int len)//翻转函数
{
for (int i = 0; i < len - 1; i++, len--)
{
char temp = arr[i];
arr[i] = arr[len - 1];
arr[len - 1] = temp;
}
}
void print_div(int len1, int len2, char* arr1, char* arr2, int* ans)
{
for(int i = len1-len2;i>=0;i--)//从最高位开始
{
while (judge(arr1 + i, arr2, len2))//判定是否可以相减
{
for (int j = 0; j < len2; j++)//高精度减法
{
if (arr1[i + j] < arr2[j])
{
arr1[i + j + 1] -= 1;
arr1[i + j] += 10;
}
arr1[i + j] -= (arr2[j] - '0');
}
ans[i]++;//ans[i]不可能>10
}
}
int len_ans = len1 - len2;//ans的长度
while (arr1[len1] == '0' && len1 > 0) len1--;//去掉前缀无用的零
while (ans[len_ans] == 0 && len_ans > 0) len_ans--;
for (int i = len_ans; i >= 0; i--)//打印商
{
printf("%d", ans[i]);
}
printf("\n");
//如果想要得到余数,则直接打印arr1即可,此时arr1存储的正是余数需要余数直接把下面的注释消掉即可
//if (len1 > 0||arr1[0]>='0')
// for (int i = len1 - 1; i >= 0; i--)
// printf("%c", arr1[i]);
}
int main()
{
scanf("%s %s", arra, arrb);
int lena = strlen(arra);//计算a和b的长度
int lenb = strlen(arrb);
my_reverse(arra, lena);
my_reverse(arrb, lenb);
print_div(lena, lenb, arra, arrb, ans);
return 0;
}
优化算法--傅里叶实现高精度乘法
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
const double PI = acos(-1.0);
struct Complex {
double x, y;
Complex(double _x = 0.0, double _y = 0.0) {
x = _x;
y = _y;
}
Complex operator-(const Complex &b) const {
return Complex(x - b.x, y - b.y);
}
Complex operator+(const Complex &b) const {
return Complex(x + b.x, y + b.y);
}
Complex operator*(const Complex &b) const {
return Complex(x * b.x - y * b.y, x * b.y + y * b.x);
}
};
/*
* 进行 FFT 和 IFFT 前的反置变换
* 位置 i 和 i 的二进制反转后的位置互换
*len 必须为 2 的幂
*/
void change(Complex y[], int len) {
int i, j, k;
for (int i = 1, j = len / 2; i < len - 1; i++) {
if (i < j) std::swap(y[i], y[j]);
// 交换互为小标反转的元素,i<j 保证交换一次
// i 做正常的 + 1,j 做反转类型的 + 1,始终保持 i 和 j 是反转的
k = len / 2;
while (j >= k) {
j = j - k;
k = k / 2;
}
if (j < k) j += k;
}
}
/*
* 做 FFT
*len 必须是 2^k 形式
*on == 1 时是 DFT,on == -1 时是 IDFT
*/
void fft(Complex y[], int len, int on) {
change(y, len);
for (int h = 2; h <= len; h <<= 1) {
Complex wn(cos(2 * PI / h), sin(on * 2 * PI / h));
for (int j = 0; j <