目录
C++算法题模板
#pragma GCC optimize(3, "Ofast", "inline")
#include <bits/stdc++.h>
using namespace std;
#define endl "\n"
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
int main()
{
IOS;
return 0;
}
#pragma GCC optimize(3, "Ofast", "inline")的作用
#pragma GCC optimize
是用来向 GCC 编译器提供特定的优化建议的指令。在这个特定的例子中,#pragma GCC optimize(3, "Ofast", "inline")
是一个优化指令,它将编译器优化级别设置为 3,启用了 Ofast 优化选项,并将函数 inline
化。
#pragma GCC optimize(3)
将优化级别设置为 3,这是 GCC 中最高的优化级别。这将启用各种复杂的优化,可能会增加编译时间,但通常会产生最快的可执行代码。"Ofast"
选项启用了一组特定的优化,通常包括了更多的浮点运算优化以及允许某些不符合标准的优化,例如忽略浮点溢出和不精确的算术。"inline"
选项告诉编译器对于适合进行内联的函数,在编译时直接将其内容嵌入调用的地方,而不是通过函数调用的方式执行,以提高执行效率。
需要注意的是,使用这些优化指令可能会使得代码的可移植性下降,因为它们依赖于编译器的特定实现和优化选项。这些指令应该谨慎使用,并且最好只在性能要求非常高且明确知道其行为影响的情况下使用。
在dev中printf和cout混用调试会崩,应避免混用
查找字符串函数
字符串和数字的相互转化
字符串转数字,使用stoi
string s("12345");
long long a = stoi(s);
cout << a << endl;
数字转字符串,使用c++里的to_string()
long long m = 1234566700;
string str = to_string(m); //系统提供数字转字符
cout << str << endl;
二维数组输出问题
字符串翻转函数
reverse(s.begin(),s.end());
,结果为ugouL
;reverse(s.begin()+1,s.end());
,结果为Lugou
;reverse(s.begin(),s.end()-2);
,结果为ouLgu
;
检查位数,回文数
bool check1(int x)//检查位数
{
if((1000 <= x && x <= 9999) || (100000 <= x && x <= 999999)) return 0;//不知道&&和||优先级的可以打个括号
return 1;
}
bool check2(int x)//检查是否回文
{
int a[20], flag = 1;//反正开得下,多开点
while (x > 0)
{
a[flag] = x % 10;
x /= 10;
flag++;
}
for (int i = 1; i <= flag / 2; i++)
if(a[i] != a[flag-i]) return 0;//不符合回文
return 1;
}
快速排序
#include<bits/stdc++.h>
using namespace std;
const int N=1e2+10;
int n;
int q[N];
void quick_sort(int q[],int l,int r)
{
if(l>=r)return;
int i=l-1,j=r+1,x=q[l];
while(i<j)
{
do i++;while(q[i]<x);
do j--;while(q[j]>x);
if(i<j)
{
int t;
t=q[i];
q[i]=q[j];
q[j]=t;
}
}
quick_sort(q,l,j);
quick_sort(q,j+1,r);
}
int main ()
{
scanf("%d",&n);
for(int i=0;i<n;i++)scanf("%d",&q[i]);
quick_sort(q,0,n-1);
for(int i=0;i<n;i++)printf("%d ",q[i]);
return 0;
}
归并排序
#include<iostream>
using namespace std;
const int N=1000010;
int n;
int q[N],tmp[N];
void merge_sort(int q[],int l,int r)
{
if(l>=r)return;
int mid=(l+r)/2;
merge_sort(q,l,mid),merge_sort(q,mid+1,r);
int k=0,i=l,j=mid+1;
while(i<=mid&&j<=r)
if(q[i]<=q[j])tmp[k++]=q[i++];
else tmp[k++]=q[j++];
while(i<=mid)tmp[k++]=q[i++];
while(j<=r)tmp[k++]=q[j++];
for(i=l,j=0;i<=r;i++,j++)q[i]=tmp[j];
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)scanf("%d",&q[i]);
merge_sort(q,0,n-1);
for(int i=0;i<n;i++)printf("%d ",q[i]);
return 0;
}
高精度乘低精度
#include<iostream>
#include<vector>
using namespace std;
vector<int> mul(vector<int>&A,int b)
{
int t=0;
vector<int> C;
for(int i=0;i<A.size()||t;i++)
{
if(i<A.size())
{
t+=A[i]*b;
}
C.push_back(t%10);
t/=10;
}
while (C.size() > 1 && C.back() == 0) C.pop_back();//去掉前导0
return C;
}
int main()
{
string a;
int b;
cin>>a>>b;
vector<int> A ;
for(int i=a.size()-1;i>=0;i--)
{
A.push_back(a[i]-'0');
}
auto C=mul(A,b);
for(int i=C.size()-1;i>=0;i--)cout<<C[i];
return 0;
}
快速幂
#include<stdio.h>
long long fastpower(long long base,long long power,long long p)
{
long long result=1;
while(power>0)
{
if(power%2==1)result=result*base%p;
base=base*base%p;
power/=2;
}
return result;
}
int main ()
{
long long a,b,p,r;
scanf("%lld %lld %lld",&a,&b,&p);
r=fastpower(a,b,p);
printf("%lld^%lld mod %lld=%lld",a,b,p,r);
return 0;
}
输出保留小数点位数
printf
支持输出保留小数点位数的数,但是很多人不知道 cout
也可以,但是需要包含头文件 iomanip
,代码:
cout << fixed << setprecision(位数) << 值;
返回回文数函数
int hw(int n)
{
int t=n;
int newt=0;
while(t)
{
newt=newt*10+t%10;
t/=10;
}
return newt;
}
sort函数
c++标准库里的排序函数的使用方法
I)Sort函数包含在头文件为#include<algorithm>的c++标准库中,调用标准库里的排序方法可以不必知道其内部是如何实现的,只要出现我们想要的结果即可!
II)Sort函数有三个参数:
(1)第一个是要排序的数组的起始地址。
(2)第二个是结束的地址(最后一位要排序的地址)
(3)第三个参数是排序的方法,可以是从大到小也可是从小到大,还可以不写第三个参数,此时默认的排序方法是从小到大排序。
Sortt函数的第三个参数可以用这样的语句告诉程序你所采用的排序原则
less<数据类型>()//从小到大排序
greater<数据类型>()//从大到小排序
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
int a[10]={9,6,3,8,5,2,7,4,1,0};
sort(a,a+10,greater<int>());
for(int i=0;i<10;i++)
cout<<a[i]<<" ";
return 0;
}
利用pair排序
(p1223排队接水部分思路)
// pair简单介绍
pair<int, double> p1; //使用默认构造函数
p1.first = 1;
p1.second = 2.5;
cout << p1.first << ' ' << p1.second << endl;//1 2.5
#include<bits/stdc++.h>
using namespace std;
bool cmp(pair<int,int>a,pair<int,int>b)
{
return a.second<b.second;
}
int main()
{
ios::sync_with_stdio(false);
vector<pair<int,int>> vec;
int n;
cin>>n;
int t;
for(int i=0;i<n;i++)
{
cin>>t;
vec.push_back({i+1,t});
}
sort(vec.begin(),vec.end(),cmp);
for (auto it = vec.begin();it != vec.end();it++)
{
cout <<it->first <<' ';
}
return 0;
}
C++获取数组最值
数组或vector最大值最小值
我们介绍库函数max_element() 及 min_element(),二者返回的都是迭代器
头文件:< algorithm >
1.求数组的最大值或最小值
1)vector容器
vector<int> nums = {1,2,3,8,0,33,11,9};
int max_num = *max_element(nums.begin(), nums.end()); //获取最大值
int min_num = *min_element(nums.begin(), nums.end());//获取最小值
2)普通数组
int nums[8] = {1,2,3,8,0,33,11,9};
int max_num = *max_element(nums, nums + 8);
int min_num = *min_element(nums, nums + 8);
2.求数组最大值最小值对应的下标
1)vector容器
vector<int> nums = {1,2,3,8,0,33,11,9};
int max_num_index = max_element(nums.begin(), nums.end()) - nums.begin(); //获取最大值对应的下标
int min_num_index = min_element(nums.begin(), nums.end()) - nums.begin();//获取最小值对应的下标
2)普通数组
int nums[8] = {1,2,3,8,0,33,11,9};
int max_num_index = max_element(nums, nums + 8) - nums;
int min_num_index = min_element(nums, nums + 8) - nums;
判断闰年
int fun(int n) // 判断闰年 yes 1 no 0
{
if((n%4==0 && n%100!=0) || n%400==0) return 1;
else return 0;
}
一个日期是一年中的第几天
int dayTest(int year,int month,int day)
{
int sum, leap;
switch (month)
{
case 1:sum = 0;
break;
case 2:sum = 31;
break;
case 3:sum = 59;
break;
case 4:sum = 90;
break;
case 5:sum = 120;
break;
case 6:sum = 151;
break;
case 7:sum = 181;
break;
case 8:sum = 212;
break;
case 9:sum = 243;
break;
case 10:sum = 273;
break;
case 11:sum = 304;
break;
case 12:sum = 334;
break;
default:printf("data error");
break;
}
sum = sum + day; // 再加上某天的天数
if (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0)) {// 判断是不是闰年
leap = 1;
} else {
leap = 0;
}
if (leap == 1 && month > 2)
{
sum++;
}
return sum;
}
子矩阵/形的数量
有一个 n×m 方格的棋盘,求其方格包含多少正方形、长方形(p2241)
如果我们固定了正方形的右下角(i,j),你能不能算出此时可能的正方形的个数?
显然,此时答案为Min(i,j)
long long sum=0;// 正方形的个数
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
sum+=min(i,j);
}
}
int fun2(int m,int n)//m,n为行列数,例如m=2,n=1,返回3,矩形总个数
{
int s=0;
for (int i = 1; i <= m; i++)
for (int p = n; p >=1; p--)s += i * p;
return s;
}
最大公约数和最小公倍数(一个有趣的写法)
int gcd(int x,int y)
{
while(x^=y^=x^=y%=x);return y;
}
int lcm(int x,int y)
{
return x*y/gcd(x,y);
}
四舍五入保留整数
printf("%d\n", (int)(r + 0.5));
比较string字符串数组中两个字符串是否一样
可以直接string[n]==string[m]
或者可以使用strcmp函数来比较两个字符串是否相同。strcmp函数会返回一个整数值,如果两个字符串相同,则返回0;如果第一个字符串小于第二个字符串,则返回一个负数;如果第一个字符串大于第二个字符串,则返回一个正数。
#include <iostream>
#include <cstring>
using namespace std;
int main() {
string str[100];
// 假设字符串数组中有两个字符串 str[0] 和 str[1]
// 进行比较
if (strcmp(str[0].c_str(), str[1].c_str()) == 0) {
cout << "两个字符串相同" << endl;
} else {
cout << "两个字符串不相同" << endl;
}
return 0;
}
请注意,strcmp函数接受的参数是const char类型,所以我们需要通过c_str()函数将string类型转换为const char类型。
判断闰年
int is_leap_year(int y)
{
if ((y %4 == 0 && y %100 != 0) || ( y% 400== 0))
return 1;
return 0;
}
swap
// 利用指针交换
void swap(int *q,int *p)
{
int t;
t=*p;
*p=*q;
*q=t;
}
// 无参交换
a = a ^ b;
b = a ^ b;
a = a ^ b;
lower_bound( )和upper_bound( )
lower_bound( )和upper_bound( )都是利用二分查找的方法在一个排好序的数组中进行查找的。
在从小到大的排序数组中,
lower_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
upper_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
在从大到小的排序数组中,重载lower_bound()和upper_bound()
lower_bound( begin,end,num,greater<type>() ):从数组的begin位置到end-1位置二分查找第一个小于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
upper_bound( begin,end,num,greater<type>() ):从数组的begin位置到end-1位置二分查找第一个小于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
#include<bits/stdc++.h>
using namespace std;
const int maxn=100000+10;
const int INF=2*int(1e9)+10;
#define LL long long
int cmd(int a,int b){
return a>b;
}
int main(){
int num[6]={1,2,4,7,15,34};
sort(num,num+6); //按从小到大排序
int pos1=lower_bound(num,num+6,7)-num; //返回数组中第一个大于或等于被查数的下标
int pos2=upper_bound(num,num+6,7)-num; //返回数组中第一个大于被查数的下标
cout<<pos1<<" "<<num[pos1]<<endl;// 3 7
cout<<pos2<<" "<<num[pos2]<<endl;// 4 15
sort(num,num+6,cmd); //按从大到小排序
int pos3=lower_bound(num,num+6,7,greater<int>())-num; //返回数组中第一个小于或等于被查数的下标
int pos4=upper_bound(num,num+6,7,greater<int>())-num; //返回数组中第一个小于被查数的下标
cout<<pos3<<" "<<num[pos3]<<endl;// 2 7
cout<<pos4<<" "<<num[pos4]<<endl;// 3 4
return 0;
}
nth_element输出第K小的数
在强大的STL库中存在一个神奇的函数,那就是nth_element,这个函数主要用来将数组元素中第k小的整数排出来并在数组中就位,随时调用,可谓十分实用。
函数语句:nth_element(数组名,数组名+第k小元素,数组名+元素个数);
执行以后数组名[k]即第K小的数,左边的都比它小,右边的都比它大,但不保证有序。
#include<bits/stdc++.h>
using namespace std;
long long n,k,a[5000010];
int main()
{
scanf("%d%d",&n,&k);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
nth_element(a,a+k,a+n);//使第k小整数就位
printf("%d",a[k]);//调用第k小整数
}
bitset输出二进制数
bitset<8> b(12); //长度为8,将12二进制保存在b中,前面位补0
判断一个数是否为2的幂
bool isPowerOfTwo(int n)
{
return n > 0 && (n & (n - 1)) == 0;
}
英文字符大小写转换函数
if (ch >= 'a' && ch <= 'z')
ch = toupper(ch);
else if (ch >= 'A' && ch <= 'Z')
ch = tolower(ch);
字符串大小比较compare
int result = str1.compare(str2);
if (result == 0)
cout << "str1 equals to str2" << endl;
else if (result < 0)
cout << "str1 is less than str2" << endl;
else
cout << "str1 is greater than str2" << endl;