using namespace std;
int main(){
}
数据类型:
整数: short,int,long long
浮点数: float,double
字符:char
布尔:bool
赋值运算符:
=,+=,-=,/=,*=
保留小数位:
cout<<fixed<<setprecision(3)<<a; a保留三位小数
printf("%.3f",a) a保留三位小数
printf("%03d",a) a不足三位前面补零
printf("%-d",a) a向左对齐
abs(a) 对整数a取绝对值
fabs(a) 对小数取绝对值
ceil(a) 对a向上取整
floor(a) 对a向下取整
setw(5) 设置宽域
单分支: if(条件成立) {执行}
双分支:if(条件成立){执行}else{条件不成立执行}
可范围多分支:if(条件1成立){执行}else if(条件2成立){执行} else{其他情况}
确定值:
switch(){
case 1:情况1执行,break;
case 2:情况2执行,break;
case 3:情况3执行,break;
default:
默认情况
}
循环:
for(int i = 1;i<=10;i++){ 1开始到10总共执行10次
循环体
}
while(条件成立){
循环
if(不成立){
break;跳出循环
}
}
do{
循环体
}while(循环成立执行)
for(int i = 1;i<=10;i++){
for(int j = 1;j<=10;j++){
循环体1
}
}
先里层在读外层
数组:
数据类型 数组名[长度]
数组初始化:
int arr[100]={1,2,3,4}
memset(数组名,初始值,sizeof(数组名))
数组排序:
sort(数组名+起点,数组名+终点+1)
排序算法:
选择排序:时间复杂度(O(n*n),不稳定排序)
每一轮选择最小的元素,和已排好的序列后一个进行交换
for (int i = 0; i < n - 1; i++) {
int minIndex = i;
for (int j = i + 1; j < n; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j;
}
}
swap(arr[minIndex], arr[i]);
}
冒泡排序:每一次如果前一个大于后一个进行交换,选出最大值(O(n*n),稳定排序)
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
// 交换
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
插入排序: 当前i 的值和前面进行比较如果比前面小,不断交换,直到不能交换为止(O(n*n),稳定排序)
for (int i=2;i<=n;i++) {
int j,k=a[i];
for (j=i-1;j>0;j--){
if (a[j]>k){
a[j+1]=a[j];
} else{
break;
}
}
a[j+1]=k;
}
快速排序:找基准点(首位/末位),每次执行比基准点小的放左边,大的放右边(O(n*logn))

邻接矩阵:
#include<bits/stdc++.h>
using namespace std;
const int N = 205;
int g[N][N];
int n,m;
int main(){
cin>>n>>m;
for(int i = 1;i<=m;i++){
int u,v;
cin>>u>>v;
g[u][v]= g[v][u]=1;
}
for(int i = 1;i<=n;i++){
for(int j = 1;j<=n;j++){
cout<<g[i][j]<<" ";
}
cout<<'\n';
}
}
邻接表
#include<bits/stdc++.h>
using namespace std;
const int N = 205;
vector<int> g[N]; // 邻接表
int n,m;
int main(){
cin>>n>>m;
for(int i = 1;i<=m;i++){
int u,v;
cin>>u>>v;
g[u].push_back(v);
}
for(int i = 1;i<=n;i++){
cout<<i<<":";
for(int j = 0;j<g[i].size();j++){
cout<<g[i][j]<<" ";
}
cout<<'\n';
}
}
字符数组:处理一串字符避免空格隔开输入问题
字符数组定义:char 数组名[长度]
注意: 字符数组最末端会添加'\0',可以用于识别字符数组末端
获取一整行字符数组(可包括空格):cin.getline(数组名,获取最大长度)
字符数组遍历:
for(int i = 0;a[i]!='\0';i++){
cout<<a[i]<<" ";
}
for(int i = 0;i<strlen(a);i++){
cout<<a[i]<<" ";
}
获取字符数组长度:strlen(数组名)
字符串:
字符串:和字符数组类似,区别不需要开辟空间,字符串末端没有加/0
字符串定义:string 字符串名
情况1: 如果输入的是不包含空格 cin>>str
情况2:如果输入包括空格: getline(cin,str);
字符串遍历:
cout<<a<<endl; // 整行输出
for(int i = 0;i<a.size();i++){ // 遍历挨个输出
cout<<a[i]<<" ";
}
获取字符串长度:str.size() / str.length()
string k = s.substr(3,3);
// 从3的位置截取子串长度为3
int k = a.find("uu"); // 查看子串uu在主串哪个位置
s.append("str"); // += 在s后面追加strs.find("str") ; // 在s字符中找str 第一个出现的位置
s.rfind("str"); // 在s字符串中找str最后一个出现的位置
s.find_first_of("0123456789"); // 查找第一个数字字符,未找到返回 stringnpos
s.find_last_of("0123456789"); // 最后一个位置出现数字
s.replace(0, 5, "hi"); // 从0开始长度为5替换成hi
字符判断:
char m = 'A';
char k ='a';
char p = '0';
char h = '&';
if(isupper(m)){ // 判断是否为大写
cout<<"大写";
}
if(islower(k)){ // 判断是否为大写
cout<<"小写";
}
if(isdigit(p)){ // 判断是否为数字
cout<<"是数字";
}
if(isalpha(h)){ // 判断是否为字母
cout<<"&是字母";
}else{
cout<<"&不是字母";
}
字符串匹配算法:
#include<bits/stdc++.h>
using namespace std;
string a = "ABAABC"; // 模式串
string b = "ABAABABAABC"; // 主串
// 获取next数组
vector<int> getnext(string &a) {
int la = a.size();
vector<int> next(la, 0);
int j = 0;
for (int i = 1; i < la; i++) {
while (j > 0 && a[i] != a[j]) {
j = next[j - 1];
}
if (a[i] == a[j]) {
j++;
}
next[i] = j;
}
return next;
}
// 求值
int kmp(vector<int>& next, string &b) {
int i = 0, j = 0;
int n = b.size();
int m = a.size();
while (i < n) {
if (a[j] == b[i]) {
i++;
j++;
} else if (j > 0) {
j = next[j - 1];
} else {
i++;
}
if (j == m) {
return i - j;
}
}
return -1;
}
int main() {
vector<int> v = getnext(a);
for (int x : v) {
cout << x << " ";
}
int k = kmp(v, b);
if (k != -1) {
cout << k << endl;
}
return 0;
}
#include<bits/stdc++.h>
using namespace std;
/*
GCD(6,12)
12/6 = 2....0
输出除数,如果余数=0
24 16
24 / 16 = 1.....8
16/8 = 2....0
除数变成被除数,余数变成除数,余数=0停止循环
输出除数
*/
int _GCD(int a,int b){ // 迭代
while(b!=0){
int temp = b;
b = a%b;
a = temp;
}
return a;
}
// 递归
int GCD(int a,int b){
return b==0?a:GCD(b,a%b);
}
// 最小公倍数
int LCM(int a,int b){
return a*b/GCD(a,b);
}
// 幂运算
long long nomer_v(int a, int b){
int res = 1;
for(int i = 1;i<=b;i++){
res *= a;
}
return res;
}
// 求幂函数快速方式
long long fase_p(int a,int b){
long long res = 1;
long long base = a;
while(b>0){
if(b%2 == 1){
res*= base;
}
base*=base;
b/=2;
}
return res;
}
// 带mod 取模快速幂
long long mod_power(int a,int b,int mod){
long long res =1;
a%=mod;
while(b>=0){
if(b%2==1){
res = (res*a)%mod;
}
a = (a*a)%mod;
}
return res;
}
int main(){
int a, b;
cin>>a>>b;
int k = mod_power(a,b,1000);
cout<<k;
}
完美匹配算法KM
int match[N]; // 右点匹配了哪个左点
int va[N], vb[N]; // 标记是否在交替路中
LL la[N], lb[N]; // 左顶标, 右顶标
LL w[N][N], d[N]; // 维护更新的delta值
bool dfs(int x) {
va[x] = 1; // x在交替路中
for (int y = 1; y <= n; y++) {
if (!vb[y]) {
if (la[x] + lb[y] - w[x][y] == 0) { // 相等子图
vb[y] = 1; // y在交替路中
if (!match[y] || dfs(match[y])) {
match[y] = x; // 配对
return 1;
}
} else { // 不是相等子图则记录最小的d[y]
d[y] = min(d[y], la[x] + lb[y] - w[x][y]);
}
}
}
return 0;
}
// 初始化权重矩阵 w
// w[x][y] = -INF; // x,y无边
// w[x][y] = z; // x,y有边
LL KM() {
// 左顶标取i的出边的最大边权
for (int i = 1; i <= n; i++) la[i] = -INF;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
la[i] = max(la[i], w[i][j]);
for (int i = 1; i <= n; i++) lb[i] = 0;
for (int i = 1; i <= n; i++) {
while (true) { // 直到左点找到匹配
fill(va + 1, va + n + 1, 0);
fill(vb + 1, vb + n + 1, 0);
fill(d + 1, d + n + 1, INF);
if (dfs(i)) break;
LL delta = INF;
for (int j = 1; j <= n; j++)
if (!vb[j]) delta = min(delta, d[j]);
for (int j = 1; j <= n; j++) { // 修改顶标
if (va[j]) la[j] -= delta;
if (vb[j]) lb[j] += delta;
}
}
}
LL res = 0;
for (int i = 1; i <= n; i++)
res += w[match[i]][i];
return res;
}
结构体笔记:
#include <bits/stdc++.h>
using namespace std;
struct Student{
string name;
int xuehao;
int math;
int china;
float english;
float total; // 总分
}s1,s[49]; // s1代表是一名学生 ,s[49] 一个班有49名
//Student s2;
//Student sk[90];
bool cmp(Student k, Student k1 ){ // k
if(k.total == k1.total){
return k.math < k1.math; // 按照数学成绩从大到小
}
return k.total>k1.total; // 前一名学生总分>后一名学生总分
}
int main(){
// 对s1这名学生添加信息
for(int i = 1;i<=5;i++){
cin>>s[i].name>>s[i].xuehao>>s[i].math>>s[i].china>>s[i].english;
s[i].total = s[i].math+s[i].china+s[i].english;
}
sort(s+1,s+6,cmp); // cmp用来自定义规则
for(int i = 1;i<=5;i++){
cout<<"姓名:"<<s[i].name<<" 成绩: "<<s[i].total<<endl;
}
// cout<<s1.name<<" "<<s1.xuehao <<" "<<s1.math<<" "<<s1.china<<" "<<s1.english;
}
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6;
int ch[N][26],cnt[N],idx;
int ne[N];
void insert(char *s){
int p=0;
for(int i = 0;s[i];i++){
int j = s[i]-'a';
if(!ch[p][j])ch[p][j]=++idx;
p = ch[p][j];
}
cnt[p]++;
}
void build() { // 用 BFS 构造 AC 自动机
queue<int> q;
// 初始化,把根节点的儿子们入队
for (int i = 0; i < 26; i++) {
if (ch[0][i]) {
q.push(ch[0][i]);
}
}
// 只要队不空
while (q.size()) {
int u = q.front(); // 节点 u 出队
q.pop();
// 枚举 u 的 26 个儿子
for (int i = 0; i < 26; i++) {
int v = ch[u][i]; // u 的第 i 个儿子
if (v) { // 1. 若儿子存在
// 则爹帮儿子建回跳边(失败指针)
ne[v] = ch[ne[u]][i];
// 并把儿子入队
q.push(v);
} else { // 2. 若儿子不存在
// 则爹自建转移边
ch[u][i] = ch[ne[u]][i];
}
}
}
}
int query(char *s) {
int ans = 0; // 初始化答案,用于统计模式串出现总次数
// 遍历主串 s 的每个字符
for (int k = 0, i = 0; s[k]; k++) {
// 1. i指针走主串对应的节点:沿着树边或转移边走,保证不回退
// 根据当前字符 s[k] 计算转移边索引,从当前节点 i 移动到下一个节点
i = ch[i][s[k] - 'a'];
// 2. j指针沿着跳边搜索模式串:从当前节点走到根节点
// 把当前节点中的所有后缀模式串一一网打尽,保证不漏解
// ~cnt[j] 等价于 cnt[j] != -1,用于判断该模式串是否已被统计过
for (int j = i; j && ~cnt[j]; j = ne[j]) {
// 累加当前节点的模式串计数到答案中
ans += cnt[j];
// 将当前节点标记为已访问,避免重复统计(设为 -1)
cnt[j] = -1;
}
}
// 3. 扫描完主串,返回答案
return ans;
}