- 最新版链接: 编程记忆3.0
C++编程记忆 3.0
0.
#include <bits/stdc++.h>
一个包含所有c/c++的头文件的头文件
gcc -mavx2 -S -fverbose-asm fun.c #看详细的汇编语言结果
#pragma GCC optimize (“O3”)
#pragma GCC target (“sse4”)
#pragma GCC optimize(“unroll-loops”)
- gdb调试
- gcc -g test.c -o o.out; gdb o.out
- 显示当前的代码: l
- 在某一行打断点: b 行号
- 查看断点信息: info b
- 根据编号删除断点: delete 7
- 根据行号删除断点: clear 7
- 开始运行程序: r (run)
- 让程序继续运行: c (continue)
- 执行单条语句: n (next)
- 逐步执行: s (step)
- 重复上条命令: 按回车
- 查看某个变量: p (print) 变量名
- 查看变量类型: whatis 变量名
- 查看函数堆栈: bt
- 结束调试: finish
- 退出调试: q
1.scanf && cin
-
%lld 对应long型变量 %d 对应 int
-
%lf 对应double型变量
-
过滤空格: c i n > > w s ; cin>>ws; cin>>ws;
-
获取输入字符
char c; getchar(); // 如果字符前有一个回车或一个空格就用getchar去掉,或者在前面加\n scanf("%c",&c); while((c=cin.get())!=EOF) map[c]++;
-
获取输入字符串
// 方法一: 在PAT上没这个函数,在VS里可以 char str[100]; gets_s(str);// 可以读取空格,回车结束;gets没有了 int N=strlen(str); // 方法二 int num=0; char ans[90][90]; while(scanf("%s",ans[num])!=EOF){num++;}// EOF为-1,num是单词个数 //方法三 #include<stack> stack<string> v; string s; while(cin>>s)v.push(s); cout<<v.pop(); // 方法四 string name; getline(cin,name); // 可读取空格 // 方法五:scanf读入string, 本方法不建议使用,可能会输出多余空格 string a; a.resize(20); scanf("%s",&a[0]); // 方法六 char s1[10000]; cin.getline(s1,100,'\n'); // 方法七 string name; getline(cin,name);
-
循环获取输入,可直接while(cin>>a>>b){}
-
忽略输入字符
scanf("%d%*c%d",&a,&b); //输入1n3,a=1,b=3,中间是字符不能是数字,可以是回车空格
-
sscanf
char a[50]; scanf("%s",a); double temp; sscanf(a,"lf",&temp); // 读出a中的double到temp sprintf(b,"%.2f",temp); // 将temp转化为二位小数的字符b // 连接功能 char str[20]; int a=20984,b=98235; ssprintf(str,"%3d%6d",a,b);// 3表示a在str中至少占3位,右对齐,6表示至少占6位
-
忽略回车
// 一次只能忽略一个 #include <numeric> #include <limits> cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
2. printf && cout
-
0xf表示16,长整数 int64_t
-
%02d 输出2位整数,不足则以0填充,%010d, 输出10位整数不足则以0填充
-
%.10f 输出10位float 或double型小数
-
%s 输出一个char一维数组
//printf输出string string str;cin>>str; printf("%s",str.c_str());
-
cout填充与精度
int n=10;char a ='b'; cout<<setw(n)<<setfill(a)<<a; int a=100; cout<<fixed<<setprecision(1)<<double(a); // 输出一位小数 cout<<setiosflags(ios::fixed)<<setprecision(2)<<res;
-
char a[11]; cin >> a; puts(a); // 即cout<<a;
-
另一种输出
#include<iterator> int A[] = { 1,4,3,7,10 }; const int N = sizeof(A) / sizeof(int); vector<int> vec(A, A + N); ostream_iterator<int> output(cout, " "); cout << "Vector vec contains:"; copy(vec.begin(), vec.end(), output); std::copy(std::begin (data), std::end(data), std::ostream_iterator<int> {std::cout, " "});
3. string
-
数字转字符串:to_string
#include <sstream> int a=1; string s=to_string(a); cout << "0" + to_string(60);
-
find
#include <cctype> string s1, s2; cin >> s1 >> s2; if(s2.find(s1[0]) == string::npos);//find的第二个参数可以是一个整数表示位置
-
rbegin
string n; cin>>n;//从后面遍历到前面 for(auto it=n.rbegin();it!=n.rend();it++) cout<<*it; // string也有begin和end
4. fill
-
二维数组填充
int e[501][501]; fill(e[0],e[0]+501*501, 123);
-
一维数组填充
int dis[501]; fill(dis,dis+501,456);
-
setfill()后面一定还要输出一个数据哪怕是一个空字符串!
int n=10;char a ='b'; cout<<setw(n)<<setfill(a)<<a;
-
字符串填充
string a,b;cin>>a>>b; int lena=a.length(),lenb=b.length(); if(lena>lenb) b.append(lena-lenb,'0'); // 往b的末尾补0直到与a等长 else a.append(lenb-lena,'0');
5. memcpy && copy&&sizeof
-
复制数组a给b
#include<string> memcpy(b,a,sizeof(int)*n); vector<int> a(5,0),b(5,0); copy(a.begin(),a.end(),b.begin()); int a[100][10]; int *b = new int[1000]; int c; cin >> c;//1000 int d[c]; int *e = (int *)malloc(sizeof(int) * 1000); cout << sizeof(a)<<" "<<sizeof(b)<<" "<<sizeof(d)<<" "<<sizeof(e)<< endl; // 4000 4 4000 4
6. struct
- 定义结构体时用了 typedef 的话,结构体定义完后的右括号后面声明的数组不可以用,去掉typedef就可以用那个结构数组了
7. vector + map
-
赋值
vector<int> o; o.push_back(123); cout<<o[0]; cout<<o.size(); o.resize(8,100); // 将第2至第8个元素赋值为100 vector<int> a(5,2); // 长度5,值为2 int in[100]={0}; vector<int> tin(in,in+10); // 把数组in前10个数push到tin里 ans.assign(res.begin(),res.end());// 都是 vector<int>类型
-
去重
// 法1 vector<char> con; sort(con.begin(), con.end()); con.erase(unique(con.begin(), con.end()), con.end()); // 删除重复元素 con.erase(con.begin()); // 删除第一个元素 // 法2 在插入时检测 if (count(con.begin(), con.end(), a[i]) == 0) // 如果不存在 con.push_back(a[i++]);
-
遍历 A16
map<string,vector<node>> custom; string str;cin>>str; vector<node> data(n); //此处省略初始化data[0] custom[str].push_back(data[0]); // 方法1 for(auto it:custom) { vector<node> temp=it.second; cout<<it.first; } // 方法二 map<string, vector<node>>::iterator it; for(it=custom.begin();it!=custom.end();it++) if(it->second==data[0]) cout << it->first <<" "; //注: map用char*做映射和string做映射不同,用char*时每赋值一次就会多一个这样的同名映射而不会合并 见A95 // 方法3 unordered_map<string, int> mp; for (auto [s, i] : mp) unordered_map<int, int> cnt; for (auto &[_, m] : cnt)
-
二维
vector<vector<int>> school(m); vector<int> school[m]; vector<<vector<int>> a( m, vector<int>(n));
-
查找
map<string, int> wordmap; string word="123"; if(wordmap.find(word) != wordmap.end()) wordmap[word]++; std::find(wordmap.begin(), wordmap.end(), "China")==wordmap.end(); wordmap.count("123");
-
取最后值
vector<int> path; _for(0, 10) path.push_back(i); cout << *(path.end()-1);
-
取前k个值(leetcode973)
vector<vector<int>> kClosest(vector<vector<int>>& points, int K) { return {points.begin(), points.begin() + k};}
-
插入
vector<int> v; v.push_bavk(123); v.push_back(456); v.insert(v.begin()+1,9);// 从第一个元素后插入9, string也可这样插入,第二个参数是字符
-
删除
vec.erase(remove(vec.begin(), vec.end(), 3), vec.end());//删除值为3的元素 typedef pair<int, int> Point; map<Point, int> cnt; cnt.erase({x, y});
-
查找
map<int, int> intervals; // 如果不存在这样的区间,interval1 为尾迭代器 auto interval1 = intervals.upper_bound(val); // 最小的且满足 l1 > val 的区间 interval1 = [l1, r1] // 最大的且满足 l0 <= val 的区间 interval0 = [l0, r0] auto interval0 = (interval1 == intervals.begin() ? intervals.end() : prev(interval1)); // interval0->first 获取key intervals.erase(interval0); intervals.emplace(left, right);
8. memset
- int c[10]; memset(c,0,40); // 只赋0和-1、1
- 在库文件cstring和string.h里
9. isxxx
- isdigit(a[i]) // a[i]是不是数字字符
- isalpha(c[j]) // c[j]是不是英文字母
- isupper(b[k])
10. 转换&& substr && stoi &&stof&& atoi &&atof&& toupper
-
获取子字符串并转数字(1)
#include <iomanip> // PAT #include<sstream> // VS stringstream ss; ss<<s.substr(5); // 取子字符串s[5]至s的结尾到容器ss中, int evalue; ss>>evalue; //转成数字
-
获取子字符串并转数字(2)
string s; cin>>s; string t = s.substr(4,3); //获取子字符串s[4]开始长为3的字符串 int n = stoi(s.substr(2));// 将s[2]至s的结尾的子字符串转化为数字,可含符号 float a= stof(s); double b= atof(s.c_str());
-
大小写转换
char a; cin >> a; cout << (char)toupper(a); string get;cin>>get; transform(get.begin(), get.end(), get.begin(), ::tolower); for (char& ch: s) if (ch >= 65 && ch <= 90) ch |= 32; // 大写转小写
-
atoi() 将char数组转成int
-
sscanf(argv[1], “%lld”, &n);
-
构造
n = strtoll(argv[1], NULL, 10);//10进制 n = strtold(argv[1], NULL); int l = strlen(argv[1]) - 1; // 输入的0的个数 int l2 = sizeof(argv[1]) - 1; // 每次都是7 cout << l << " " << l2 << endl; cout << argv[2] << endl; n = 1; while (l--) n *= 10;
-
将int转char数组
int x; cin>>x; char s[100]; snprintf(s, sizeof(s), "%0100d", x); itoa(x,s,10); // 第三个参数是进制,可能有的不支持 cout<<x;
-
long long d = 1LL * nums[i] - nums[j]
-
char转string:string s = “123”; string a = string(1, s[1]); s.push_back(s[0]);
11. reverse
-
反转字符串
string s;cin>>s; reverse(s.begin(),s.end());
-
传vector
vector<int> a(5); a[0]=1;a[1]=2;a[2]=3;a[3]=4;a[4]=5; reverse(begin(a)+2,begin(a)+5); // 不包括右边
12. sort
-
快速排序
bool cmp(int a,int b) {return b>a;} // 降序 vector<int> v; for(int i=0;i<100;i++)v.push_back(rand()); sort(v.begin(),v.end(),cmp); for(int i=0;i<100;i++) cout<<v[i]<<" ";
-
降序
sort(a, a+n, greater<int>()); // less<int>() sort(nums.begin(), nums.end(), greater<>()); // vector<int> &nums
-
简写
sort(p, p + n, [](const project& p1, const project& p2) {return p1.d < p2.d; }); // 按值传递r0、c0,也可以用&r0 sort(ret.begin(), ret.end(), [r0,c0](vector<int>& a, vector<int>& b) { return abs(a[0] - r0) + abs(a[1] - c0) < abs(b[0] - r0) + abs(b[1] - c0);}); sort(nums.begin(), nums.end(), [](const int &x, const int &y) { long sx = 10, sy = 10; while (sx <= x) sx *= 10; while (sy <= y) sy *= 10; return sy * x + y > sx * y + x; }); // vector<string> dic 按长度降序、按字典序升序排列 sort(dic.**r**begin(), dic.**r**end(), [](auto&& a, auto&& b){ return a.size() < b.size() || a.size() == b.size() && a > b;});
-
稳定排序
// vector<string> words; stable_sort(begin(words), end(words), [](auto&& a, auto&& b){return a.size() < b.size();});
13. strcmp
-
int strcmp(const char* s1, const char* b); // s1<s2时返回负数,相等时返回0
char a[10],c[4]="123"; //三个a都会输出 if(strcmp(a,c)==0) cout<<a; if(strcmp(a,"123")==0)cout<<a; if(strcmp(a,"123\0")==0)cout<<a;
14. round
-
四舍五入
int a,b,c;cin>>a>>b>>c; a=round((a+b+c)/3.0)+0.5;
15. 二分查找
-
从小到大排序,第一个大于b的数的下标
int j=upper_bound(a,a+n,b)-a;// j-1 就是第一个小于等于b的数的下标
-
从大到小排序,第一个小于b的数的下标
int it_i = upper_bound(a.begin(), a.end(), b, greater<int>())-a.begin(); //再减一就是最后一个大于等于b的数的下标
-
从小到大排序,第一个大于等于b的数的下标
int k=lower_bound(a.begin(), a.end(),b)-a.begin(); // 从小到大排序,第一个大于等于b的数的下标 set<int> available; auto p = available.lower_bound(b); // 大于等于b的最小数
-
从大到小排序,第一个小于等于b的数的下标
int it_j = lower_bound(a.begin(), a.end(), b, greater<int>())-a.begin(); //再减一就是最后一个大于b的数的下标
16. freopen
-
打开文件
freopen("file.in","r",stdin); freopen("file.out","w",stdout);
17. set
-
插入
#include<set> set<int> s; s.insert(123);
-
删除
set<node> s; auto it = s.find(node{num, book[num]}); if (it != s.end()) s.erase(it); s.erase(s.begin()); // 删除最小值 // 最小值 *s.begin() 最大值 *s.rbegin()
-
用于加快查找
vector<string> wordList; string t="123"; unordered_set<string> wordSet(wordList.begin(),wordList.end()); //if(std::find(wordList.begin(),wordList.end(),t)!=wordList.end()){...} if(wordSet.count(t)){...}
-
找倒数第二个数
set<int> st; cout<<*prev(prev(st.end()));
-
遍历
set<char>::iterator iter = temp.begin(); while (iter!=temp.end()) { cout<<*iter; iter++; }
-
插入+查找
unordered_set<long> seen; if (seen.insert(next).second) // 如果之前没有插入过 heap.push(next);
18. 运算符重载
struct node {
int value; int cnt;
bool operator < (const node & a) const{
return cnt != a.cnt ? cnt > a.cnt:value < a.value;
}
};
set<node> s; // s插入时会自动调用<排序
struct plural {
int a, b;
plural() { a = 0, b = 0; }
plural(int A, int B) : a(A), b(B) {}
friend istream &operator>>(istream &in, plural &p) {
in >> p.a >> p.b;
return in;
}
friend ostream &operator<<(ostream &out, plural &p) {
out << p.a;
if (p.b > 0)out << "+";
out << p.b << "i";
return out;
}
friend plural operator+(const plural &A, const plural &B) {
plural p(A.a + B.a, A.b + B.b);
return p;
}
friend void operator+=(plural &A, const plural &B) {
A.a += B.a;
A.b += B.b;
}
friend plural operator*(const plural &A, const plural &B) {
plural p(A.a * B.a - A.b * B.b, A.a * B.b + A.b * B.a);
return p;
}
friend void operator*=(plural &A, const plural &B) {
plural p(A.a * B.a - A.b * B.b, A.a * B.b + A.b * B.a);
A = p;
}
};
19. auto it
// 用箭头
for(auto it = s.begin();it != s.end(); it++)
printf(" %d", it->value);
// 用小数点
for (auto it : s)
cout << " " << it.value;
// 值拷贝
vector<vector<int>> matrix;
auto matrix_new = matrix;
maxtrix = matrix_new;
20. pair
#include<utility>
pair<string, int> name_age("Tom", 18);
name_age.first="Sam";
name_age=make_pair("Bob",19);
21. 优先级队列
priority_queue<**tuple**<double, int, int>> q;
priority_queue<pair<int, int>> q;// 大根堆,python是小根堆
q.emplace(197, 0); // 按第一个值建堆,第二个值表示197在原来的数组中的索引
cout<<q.top().first; // 堆顶元素的值最大
auto cmp = [&](const char& letter1, const char& letter2) {
return counts[letter1 - 'a'] < counts[letter2 - 'a'];
};
// 按cmp排序建大根堆,第二个元素存堆,必须用vector
priority_queue<char, vector<char>, decltype(cmp)> queue{cmp}; // {}用()也行
queue.push('a');
priority_queue<int, vector<int>, less<int>> queMin;// 大根堆
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<>> pq; // 小根堆
pq.emplace(0, k - 1);
auto p = pq.top();
pq.pop();
// 小根堆
vector<pair<int, int>> power;
priority_queue q(greater<pair<int, int>>(), move(power));
22. char*处理
-
strcpy
char* date=new char[9]; const char* month; mon="November"; strcpy(date,month); // const char* 转char*
23. max_element&&accumulate
unordered_map<char, int> freq;
int maxExec = max_element(freq.begin(), freq.end(), [](const auto& u, const auto& v) {return u.second < v.second;})->second;
#include <numeric>
int maxCount = accumulate(freq.begin(), freq.end(), 0, [=](int acc, const auto& u) {return acc + (u.second == maxExec);}); // maxExec出现次数
long long sum = accumulate(res[0].begin(), res[0].end(), 0ll); // 对二维vector的第0行求和
24. 单调队列
deque<int> opt = {0,0};
int f = opt.front();
int b = opt.back();
opt.push_back(1);
opt.pop_front();
opt.pop_back();
25. tie (c++17)
// 无需显示定义中间变量 | 矩阵翻转的例子
tie(matrix[i][j], matrix[n - j - 1][i], matrix[n - i - 1][n - j - 1], matrix[j][n - i - 1]) \
= make_tuple(matrix[n - j - 1][i], matrix[n - i - 1][n - j - 1], matrix[j][n - i - 1], matrix[i][j]);
26. iota
#include<numeric>
int numbers[10]; // 也可以是vector
std::iota (numbers,numbers+10,100); // 从100开始赋值,累加到109
vector<int> ans(n);
iota(ans.begin(), ans.end(), 0);
27. 简写实现函数
vector<vector<int>> points;
auto dist = [&](int x, int y) -> int {
return abs(points[x][0] - points[y][0]) + abs(points[x][1] - points[y][1]);};
// 递归实现函数内部函数,返回值是void,输入两个int
function<**void(int, int)**> backtrack = [&](int pos, int mask) {
if (pos == masks.size()) {
ans = max(ans, __builtin_popcount(mask)); // 求1的个数
return;
}
if ((mask & masks[pos]) == 0) { // mask 和 masks[pos] 无公共元素
backtrack(pos + 1, mask | masks[pos]);
}
backtrack(pos + 1, mask);
};
// 检查是否是元音字符 isVowel('a')
auto isVowel = [vowels = "aeiouAEIOU"s](char ch) {
return vowels.find(ch) != string::npos;
};
function<int(int)> f = [&](int x){
if(x==1) return 2;
else if(x==2) return 4;
else return f(x-1)+f(x-2);
};
28. 红黑树(求最大值最小值)
multiset<int> s;
s.insert(1); // 相同时是插在右边
int maxs=*s.rbegin();
int mins=*s.begin();
s.erase(s.find(1));
29. any_of
unordered_map<int, int> freq;
if (any_of(freq.begin(), freq.end(), [](const auto& entry) {return entry.second != 0;})) return false;
30. __builtin_popcount
return __builtin_popcount(x ^ y);// x和y的二进制中不同位的个数
31. array 二维数组
static constexpr array<array<int, 6>, 2> dist = {{
{0, 1, 2, 1, 2, 3},
{3, 2, 1, 2, 1, 0}
}}; // 括号不能省
array<int, 26> cnt{};
32. 自定义map
// map: array<int, 26> 转 int 转 vector<string>
// 自定义对 array<int, 26> 类型的哈希函数
auto arrayHash = [fn = hash<int>{}] (const array<int, 26>& arr) -> size_t {
return accumulate(arr.begin(), arr.end(), 0u, [&](size_t acc, int num) {
return (acc << 1) ^ fn(num);
});
};
unordered_map<array<int,26>,vector<string>,decltype(arrayHash)> mp(0, arrayHash);
array<int, 26> counts{};
for (int i = 0; i < str.length(); ++i)
counts[str[i] - 'a'] ++;
mp[counts].emplace_back(str);
33. 高效位运算
// 在函数名后面加上l或ll代表传入unsigned long/unsigned long long
// 求mask中从右数第一个1右边0的个数
int i=__builtin_ctz(mask);
// 求mask中从左数第一个1左边0的个数
int i=__builtin_clz(mask);
// 最后一位1是从右数第几位
int i=__builtin_ffs(mask);
// 二进制中1的个数
int i=__builtin_popcount(mask);
// 奇偶校验位,mask的1的个数模2的结果
int i=__builtin_parity(mask);
__builtin_clz(num) // 前导0的个数
// 实现
int zeros(unsinged int num) {
unsinged int clz = 0;
if ((num >> 16) == 0) {
clz += 16;
num <<= 16;
}
if ((num >> 24) == 0) {
clz += 8;
num <<= 8;
}
if ((num >> 28) == 0) {
clz += 4;
num <<= 4;
}
if ((num >> 30) == 0) {
clz += 2;
num <<= 2;
}
if ((num >> 31) == 0) {
clz += 1;
}
return clz;
}
__builtin_popcount(num) // 二进制中1的个数
int count(int num) {
num = (num & 0x55555555) + ((num >> 1) & 0x55555555); // 相邻两位上的1的和存在这两位上
num = (num & 0x33333333) + ((num >> 2) & 0x33333333);
num = (num & 0x0F0F0F0F) + ((num >> 4) & 0x0F0F0F0F);
num = (num & 0x00FF00FF) + ((num >> 8) & 0x00FF00FF);
num = (num & 0x0000FFFF) + ((num >> 16) & 0x0000FFFF);
return num;
}
34. 宏
#define _for(i,a,b) for( int i=(a); i<(b); ++i)
#define __for(i,a,b) for( int i=(a); i<=(b); ++i)
#define mfor(i,a,b) for(int i=(a);i>(b);--i)
#define mmfor(i,a,b) for(int i=(a);i>=(b);--i)
35. 求前缀和
vector<int> pre; // pre[i]=pre[i-1]+w[i]
partial_sum(w.begin(), w.end(), back_inserter(pre)); // vector<int> w
36. 均匀分布 随机生成数
mt19937 gen=random_device{}();
uniform_int_distribution<int> dis(1, accumulate(w.begin(), w.end(), 0)); // 1 ~ vector<int> w 求和
int x = dis(gen);
37. using &&
using u = unsigned int;
39. tuple
tuple<int, int, int> runLoc = make_tuple(hid, cid, hostCoreBlock[hid][cid]++);
int first = get<0>(runLoc[i][j]); // C++ 17 / 20
38. find_if
auto check = [&](string& x){
if(x.length()==1)
return true;
return false;
};
// vector<string>& dic
string s = *find_if(begin(dic), end(dic), check);
40. 函数传参
int binarySearch(int n, function<bool(int)> f) {
int l = 0, r = n;
while (l < r) {
int mid = (l + r) / 2;
if (f(mid))
r = mid;
else
l = mid + 1;
}
return l;
}
vector<vector<int>> d;
// 找第一个大于等于v的 i (d每行最后一个数是升序的)
int i = binarySearch(d.size(), [&](int i) { return d[i].back() >= v; });
// 找i-1行里第一个小于v的数的位置k (d每行降序排列)
int k = binarySearch(d[i - 1].size(), [&](int k) { return d[i - 1][k] < v; });
41. 极值 最值
long a = LONG_MIN;
#include<limits.h>
#define INT_MAX 2147483647
#define INT_MIN (-INT_MAX - 1)
42. list
list<int> lst(nums.begin(), nums.end()); // vector<int> nums
auto it = lst.begin();
advance(it, j); // 移动到第j位
shuffled[i] = *it;
lst.erase(it);
43. sleep
// windows
#include<windows.h>
Sleep(2000);
// linux
#include <unistd.h>
sleep(1); // 秒
usleep(1);// 微秒
44. all_of
int cnt[26]{};
return all_of(cnt, cnt + 26, [](int x){return x >= 0;});
45. 异常捕获
int main()
try {
}
catch (std::exception& e) {
std::cout<< e.what() << std::endl;
}
46. bind
#include <functional>
int fun(int a, int b, int c, int d);
auto f = std::bind(fun, 100, std::placeholders::_2, 300, std::placeholders::_1);
f(200, 400);// 输出 100 400 300 200
47. for_each
std::for_each(std::begin(arr), std::end(arr), [](int& a) { std::cout << a << "\t"; });
48. 自定义hash
auto hash_fn = [fn = hash<long long>()](const pair<int, int>& o) -> size_t {
auto& [x, y] = o;
return fn((long long)x << 20 | y);
};
unordered_set<pair<int, int>, decltype(hash_fn)> hash_blocked(0, hash_fn);
for (const auto& pos: blocked) { // vector<vector<int>> blocked
hash_blocked.emplace(pos[0], pos[1]);
}
auto hash_p = [](const pair<int, int> &p) -> size_t {
static hash<long long> hash_ll;
return hash_ll(p.first + (static_cast<long long>(p.second) << 32));
};
unordered_set<pair<int, int>, decltype(hash_p)> points(0, hash_p);
49. stringstream 字符流
stringstream ss(s); // string s
string word;
while (ss >> word) { // 按空格隔开
++freq[move(word)];
}
50. 前导0的个数 和 二进制中1的个数
51. 正则
regex re("\\+|i"); // 根据 + 和 i 分开字符串 num1 string
vector<string> complex1(sregex_token_iterator(num1.begin(), num1.end(), re, -1), std::sregex_token_iterator());
其他
-
long double 可用于 [−263,263]的加减法,只用double却不行,A1065
-
ASCII部分
-
char数组赋值
char s[14] = {"0123456789JQK"}; //数组长度不可以是s[13],但那下面这种可以是c[13] char c[14] = { '0','1','2','3','4','5','6','7','8','9','j','q','k' }; const char *str[4] = { "aaa", "bbb", "ccc", "ddd"};
-
声明、初始化和释放string二维动态数组
int n,m; cin>>n>>m; // n行m列的string二维数组 string** ss=new string*[n]; for(int i=0;i<n;i++) ss[i]=new string[m]; // 赋值 string *q=ss[0]; // 1 string *w=*ss; // 2 string *ww=*ss+2; // 2 string s[5][6]; string(*e)[6]=s; // 3 int b[6]={0}; int *c=b; // 4 for(int i=0;i<n;i++) delete[] ss[i]; delete[] ss; vector<<vector<int>> a( m, vector<int>(n));
-
typedef long long ll;
当你走投无路时
- 考虑变量是否越界访问数组,调大数据表示范围,记得输入(scanf)输出也要改
- 考虑是否输出有规定位数限制,用 cout 时要用 setw 和 setfill 填充
- 考虑边界值,比如 +0 与 - 0
- 看看输出格式,检查单词是否拼错,漏了个字母,大小写
- 如果在for循环里用了vector的 size() 函数还 -1, 要小心size为 0 时 -1 结果不是负一 ,建议转为int,比如:(int)nums.size() - 1
- 当用了很多数组或vector、取数组元素时用的下标是另一个数组的值时,要特别注意所代表的含义是否正确
- 是否改变了输入的数据结构没有还原,比如用Morris算法中序遍历 验证二叉搜索树 一定要还原完再返回
模板
-
并查集
class UF { public: vector<int> fa; vector<int> sz; // 按秩合并 int n; int comp_cnt; public: UF(int _n): n(_n), comp_cnt(_n), fa(_n), sz(_n, 1) { iota(fa.begin(), fa.end(), 0); } int findset(int x) { return fa[x] == x ? x : fa[x] = findset(fa[x]); } bool unite(int x, int y) { x = findset(x); y = findset(y); if (x == y) { return false; } if (sz[x] < sz[y]) { swap(x, y); } fa[y] = x; sz[x] += sz[y]; --comp_cnt; return true; } bool connected(int x, int y) { x = findset(x); y = findset(y); return x == y; } };
-
线段树
struct SegTree{//zkw线段树 const static int X=1<<17; int data[1<<18]={0}; SegTree(vector<int>°map){ memcpy(data+X,°map[0],degmap.size()*sizeof(int)); for(int i=X-1;i;i--)data[i]=data[i*2]+data[i*2+1]; } void update(int i,int inc){ for(i+=X;i;i>>=1){ data[i]+=inc; } } int query(int left,int right){ if(left>right)return 0; if(left==right)return data[left+X]; left=max(left,0); int sum=data[left+=X]+data[right+=X]; while((left>>1)!=(right>>1)){ if(left%2==0)sum+=data[left+1]; if(right%2)sum+=data[right-1]; left>>=1; right>>=1; } return sum; } }; int deg[10000]; int maxdeg=*max_element(deg,deg+10000); vector<int> degmap(maxdeg+1,0); for(int i=0;i<10000;i++) degmap[deg[i]]++; SegTree T(degmap); for(int i=0;i<n;i++){ // 查找deg中两数之和大于sum的对数 //将自己的度数从度数分布里去除,因为自己不能充当自己的配对 T.update(deg[i],-1); //此时树中的所有度数都是编号比自己大的结点的度数,因为for之前的查询update了 //累加的范围要求:目标度数加上deg[i]要比sum大 res+=T.query(sum+1-deg[i],maxdeg); // 区间和 } 作者:oldyan 链接:https://leetcode-cn.com/problems/count-pairs-of-nodes/solution/yi-yu-li-jie-de-xian-duan-shu-zuo-fa-by-5sh80/ #include <iostream> #include <cstdio> #include <cmath> #include <cstring> using namespace std; namespace SegTree { #define maxn 1000000 class SegmentTree { #define lson (o<<1) #define rson (o<<1|1) #define mid ((l+r)>>1) public : int addv[maxn], maxv[maxn], minv[maxn], sumv[maxn]; int arr[maxn]; int N; private:int _max(const int& _, const int& __) { return _>__?_:__; } private:int _min(const int& _, const int& __) { return _<__?_:__; } public : int pushup(int o) { minv[o] = _min(minv[lson], minv[rson]); maxv[o] = _max(maxv[lson], maxv[rson]); sumv[o] = sumv[lson] + sumv[rson]; return 0; } public : int pushdown(int o, int l, int r) { if(addv[o] == 0) return -1; addv[lson] += addv[o]; addv[rson] += addv[o]; minv[lson] += addv[o]; minv[rson] += addv[o]; maxv[lson] += addv[o]; maxv[rson] += addv[o]; sumv[lson] += addv[o] * (mid-l+1); sumv[rson] += addv[o] * (r-mid); addv[o] = 0; } public : int Build(int o, int l, int r) { addv[o] = 0; if(l == r) { maxv[o] = arr[l];minv[o] = arr[l];sumv[o] = arr[l]; return 0; } Build(lson, l, mid); Build(rson, mid+1, r); pushup(o); return 0; } public : int optadd(int o, int l, int r, int ql, int qr, int addval) { if(ql > r or qr < l) return 0; if(ql <= l and r <= qr) { addv[o] += addval; sumv[o] += addval * (r-l+1); return 0; } pushdown(o, l, r); optadd(lson, l, mid, ql, qr, addval); optadd(rson, mid+1, r, ql, qr, addval); pushup(o); } public : int query_sum(int o, int l, int r, int ql, int qr) { if(ql > r or qr < l) return 0; if(ql <= l and r <= qr) { return sumv[o]; } pushdown(o, l, r); return query_sum(lson, l, mid, ql, qr) + query_sum(rson, mid+1, r, ql, qr); } public : int query_min(int o, int l, int r, int ql, int qr) { if(ql > r or qr < l) return 0; if(ql <= l and r <= qr) { return minv[o]; } pushdown(o, l, r); return _min(query_min(lson, l, mid, ql, qr), query_min(rson, mid+1, r, ql, qr)); } public : int query_max(int o, int l, int r, int ql, int qr) { if(ql > r or qr < l) return 0; if(ql <= l and r <= qr) { return maxv[o]; } pushdown(o, l, r); return _max(query_max(lson, l, mid, ql, qr), query_max(rson, mid+1, r, ql, qr)); } }; } //End of SegmentTree using namespace SegTree; // https://zh.wikipedia.org/wiki/%E7%B7%9A%E6%AE%B5%E6%A8%B9 class NumArray { private: vector<int> segmentTree; int n; void build(int node, int s, int e, vector<int> &nums) { if (s == e) { segmentTree[node] = nums[s]; return; } int m = s + (e - s) / 2; build(node * 2 + 1, s, m, nums); build(node * 2 + 2, m + 1, e, nums); segmentTree[node] = segmentTree[node * 2 + 1] + segmentTree[node * 2 + 2]; } void change(int index, int val, int node, int s, int e) { if (s == e) { segmentTree[node] = val; return; } int m = s + (e - s) / 2; if (index <= m) { change(index, val, node * 2 + 1, s, m); } else { change(index, val, node * 2 + 2, m + 1, e); } segmentTree[node] = segmentTree[node * 2 + 1] + segmentTree[node * 2 + 2]; } int range(int left, int right, int node, int s, int e) { if (left == s && right == e) { return segmentTree[node]; } int m = s + (e - s) / 2; if (right <= m) { return range(left, right, node * 2 + 1, s, m); } else if (left > m) { return range(left, right, node * 2 + 2, m + 1, e); } else { return range(left, m, node * 2 + 1, s, m) + range(m + 1, right, node * 2 + 2, m + 1, e); } } public: NumArray(vector<int>& nums) : n(nums.size()), segmentTree(nums.size() * 4) { build(0, 0, n - 1, nums); } void update(int index, int val) { change(index, val, 0, 0, n - 1); } int sumRange(int left, int right) { return range(left, right, 0, 0, n - 1); } }; // https://leetcode-cn.com/problems/range-sum-query-mutable/solution/qu-yu-he-jian-suo-shu-zu-ke-xiu-gai-by-l-76xj/
-
逆元求组合数
//1
ll fac[MAXE],inv[MAXE];
const ll mod=ll(1e9+7);
ll Qpow(ll a,ll p)
{
ll res=1;
while(p)
{
if(p&1)res=(res*a)%mod;
a=(a*a)%mod;
p>>=1;
}
return res;
}
ll C(ll n,ll m)//组合数
{
return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
fac[0]=1,inv[0]=1;
for(ll i=1;i<MAXE;++i)//预处理阶乘&组合数
{
fac[i]=fac[i-1]*i%mod;
inv[i]=Qpow(fac[i],mod-2);
}
//链接:https://www.acwing.com/solution/content/7261/
//2
const int N = 1e5 + 10,M = 2e3 + 10,mod = 1e9 + 7;
int fac[N << 1],invfac[N << 1];
int C(int n,int m){return n<m?0:(long long)fac[n]*invfac[m]%mod*invfac[n-m]%mod;}
void init(){
fac[0]=invfac[0]=invfac[1]=1;
for(int i=1;i<=2e5 + 10;i++)fac[i]=(long long)fac[i-1]*i%mod;
for(int i=2;i<=2e5 + 10;i++)invfac[i]=(long long)(mod-mod/i)*invfac[mod%i]%mod;
for(int i=2;i<=2e5 + 10;i++)invfac[i]=(long long)invfac[i-1]*invfac[i]%mod;
}
//链接:https://www.acwing.com/solution/content/17704/
- 快读快写
#define ll long long int
inline ll read(){
ll s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
inline void out(ll a)
{
if(a>=10)out(a/10);
putchar(a%10+'0');
}
- AVL
-
树状数组
class StreamRank { public: int arr[50005]; StreamRank() { for(int i=0;i<50005;i++){ arr[i]=0; } } void track(int x) { x++; for(int i=x;i<50005;i+=i&(-i)){ arr[i]++; } return ; } int getRankOfNumber(int x) { int res=0; for(int i=x+1;i;i-=i&(-i)){ res+=arr[i]; } return res; } }; /** * Your StreamRank object will be instantiated and called as such: * StreamRank* obj = new StreamRank(); * obj->track(x); * int param_2 = obj->getRankOfNumber(x); */ class NumArray { // 求区间和 private: vector<int> tree; vector<int> &nums; int lowBit(int x) { return x & -x; } void add(int index, int val) { while (index < tree.size()) { tree[index] += val; index += lowBit(index); } } int prefixSum(int index) { int sum = 0; while (index > 0) { sum += tree[index]; index -= lowBit(index); } return sum; } public: NumArray(vector<int>& nums) : tree(nums.size() + 1), nums(nums) { for (int i = 0; i < nums.size(); i++) { add(i + 1, nums[i]); } } void update(int index, int val) { add(index + 1, val - nums[index]); nums[index] = val; } int sumRange(int left, int right) { return prefixSum(right + 1) - prefixSum(left); } }; 作者:LeetCode-Solution 链接:https://leetcode-cn.com/problems/range-sum-query-mutable/solution/qu-yu-he-jian-suo-shu-zu-ke-xiu-gai-by-l-76xj/ // 区间修改,单点查询(此处用差分数组) add(l, val); add(r+1, -val); ans = nums[x]+prefixSum(x); // 区间修改,区间查询 class TreeArray { private: int n; vector<int> tree1; vector<int> tree2; inline int lowbit(int x) { return x & (-x); } void updata(int i, int val) { for (int p = i; i <= n; i += lowbit(i)) { tree1[i] += val; tree2[i] += p*val; } } int query(int i) { int sum = 0; for (int n = i; i > 0; i -= lowbit(i)) { sum += (n+1)*tree1[i] - tree2[i]; } return sum; } public: TreeArray() {} TreeArray(int n):n(n), tree1(n+1), tree2(n+1) {} // 区间修改 void rangeUpdata(int left, int right, int val) { updata(left, val); updata(right+1, -val); } // 区间查询 int rangeQuery(int left, int right) { return query(right) - query(left-1); } };
$=\sum_i \{(n+1)D[i]- iD[i]\}$
-
字典树模板
struct TrieNode { string word; unordered_map<char,TrieNode *> children; TrieNode() { this->word = ""; } }; void insertTrie(TrieNode * root,const string & word) { TrieNode * node = root; for (auto c : word){ if (!node->children.count(c)) { node->children[c] = new TrieNode(); } node = node->children[c];upper_bound } node->word = word; } // 数组版 constexpr int MN = 8E4, M = 26, ML = 1000 + 1; int top, tree[MN][M]; bool isEnd[MN];// vis[ML]; int getNext() { isEnd[++top] = 0; memset(tree[top], 0, sizeof tree[top]); return top; } void insert(const string& s) { int rt = 1; for (char c : s) { c -= 'a'; if (tree[rt][c]) rt = tree[rt][c]; else rt = tree[rt][c] = getNext(); } isEnd[rt] = 1; }