蓝桥杯考前冲刺
一,奇技淫巧
1.手写:1.迷宫 - 蓝桥云课 (lanqiao.cn)
直接画图
2.word查找:1.门牌制作 - 蓝桥云课 (lanqiao.cn)
3.处理日期:1.星期一 - 蓝桥云课 (lanqiao.cn)
excel:
python:
from datetime import *
dt1=datetime(1901,1,1)
dt2=datetime(2000,12,31)
print(dt1.weekday())
1
td=dt2-dt1
print(td)
36524 days, 0:00:00
print(td//7)
5217 days, 17:08:34.285714
print(td.days//7)
5217
4.大数处理:1.乘积尾零 - 蓝桥云课 (lanqiao.cn)
import os
import sys
data="5650 4542 3554 473 946 4114 3871 9073 90 4329 \
2758 7949 6113 5659 5245 7432 3051 4434 6704 3594 \
9937 1173 6866 3397 4759 7557 3070 2287 1453 9899 \
1486 5722 3135 1170 4014 5510 5120 729 2880 9019 \
2049 698 4582 4346 4427 646 9742 7340 1230 7683 \
5693 7015 6887 7381 4172 4341 2909 2027 7355 5649 \
6701 6645 1671 5978 2704 9926 295 3125 3878 6785 \
2066 4247 4800 1578 6652 4616 1113 6205 3264 2915 \
3966 5291 2904 1285 2193 1428 2265 8730 9436 7074 \
689 5510 8243 6114 337 4096 8199 7313 3685 211 "
num=data.split()
s=1
for i in num:
s=s*int(i)
cnt=0
while s%10==0:
s//=10
cnt+=1;
print(cnt)
5.字符串处理:1.平方和 - 蓝桥云课 (lanqiao.cn)
sum=0
for i in range(1,2019+1):
s=str(i)
if '0' in s or '2' in s or '1' in s or '9' in s:
sum+=i*i
print(sum)
6.手算找规律:1.切面条 - 蓝桥云课 (lanqiao.cn)
#include<bits/stdc++.h>
using namespace std;
int main()
{
cout<<pow(2,10)+1<<endl;
return 0;
}
7.付账问题贪心:1.付账问题 - 蓝桥云课 (lanqiao.cn)
#include <bits/stdc++.h>
using namespace std;
const int N=500005;
int a[N];
int main()
{
int n;int sum_;cin>>n;cin>>sum_;
for(int i=0;i<n;i++)
{
cin>>a[i];
}
sort(a,a+n);
double avg=1.0*sum_/n; //转化成小数
double ssum=0;
//进行分类一个是钱数<=avg的,另一个是钱的数量>avg的,需要全部拿出来
//现在我们的数据具有性质了
for(int i=0;i<n;i++)
{
if(a[i]*(n-i)<sum_) //这里是因为总数是n个吧,然后第一次变为了 a[i]*n<sum_的情况 第二次sum_发生了更新此时sum_已经减去了a[0]的数据所以这里自然是a[i]*(n-1)<新sum_
{
ssum+=(a[i]-avg)*(a[i]-avg);
sum_-=a[i];
}
else//此时已经全部够了
{
double cur_avg=1.0*sum_/(n-i);
ssum+=(avg-cur_avg)*(avg-cur_avg)*(n-i);
break;
}
}
printf("%.4lf",sqrt(ssum/n));
return 0;
}
#include <bits/stdc++.h>
using namespace std;
const int N=500005;
long long a[N];
int main()
{
int n;long long sum_;cin>>n;cin>>sum_;
for(int i=0;i<n;i++)
{
cin>>a[i];
}
sort(a,a+n);
double avg=1.0*sum_/n; //转化成小数
double ssum=0;
//进行分类一个是钱数<=avg的,另一个是钱的数量>avg的,需要全部拿出来
//现在我们的数据具有性质了
for(int i=0;i<n;i++)
{
if(a[i]*(n-i)<sum_) //这里是因为总数是n个吧,然后第一次变为了 a[i]*n<sum_的情况 第二次sum_发生了更新此时sum_已经减去了a[0]的数据所以这里自然是a[i]*(n-1)<新sum_
{
ssum+=(a[i]-avg)*(a[i]-avg);
sum_-=a[i];
}
else//此时已经全部够了
{
double cur_avg=1.0*sum_/(n-i);
ssum+=(avg-cur_avg)*(avg-cur_avg)*(n-i);
break;
}
}
printf("%.4lf",sqrt(ssum/n));
return 0;
}
#include <bits/stdc++.h>
using namespace std;
const int N=500005;
int a[N];
int main()
{
int n;long long sum_;cin>>n;cin>>sum_;
for(int i=0;i<n;i++)
{
cin>>a[i];
}
sort(a,a+n);
double avg=1.0*sum_/n; //转化成小数
double ssum=0;
//进行分类一个是钱数<=avg的,另一个是钱的数量>avg的,需要全部拿出来
//现在我们的数据具有性质了
for(int i=0;i<n;i++)
{
if((long long)a[i]*(n-i)<sum_) //这里是因为总数是n个吧,然后第一次变为了 a[i]*n<sum_的情况 第二次sum_发生了更新此时sum_已经减去了a[0]的数据所以这里自然是a[i]*(n-1)<新sum_
{
ssum+=(a[i]-avg)*(a[i]-avg);
sum_-=a[i];
}
else//此时已经全部够了
{
double cur_avg=1.0*sum_/(n-i);
ssum+=(avg-cur_avg)*(avg-cur_avg)*(n-i);
break;
}
}
printf("%.4lf",sqrt(ssum/n));
return 0;
}
这里int范围虽然没有爆int但是出现一个问题:a[i]*(n-i)如果不发生强制类型转换的话会爆出int
8.普通:1.纸张尺寸 - 蓝桥云课 (lanqiao.cn)
#include <bits/stdc++.h>
using namespace std;
int main()
{
int long_=1189,short_=841;
char a;int b;
cin>>a>>b;
while(b--)
{
long_ /=2;
if(short_>long_)
swap(short_,long_);
}
cout<<long_<<endl<<short_<<endl;
return 0;
}
9.普通:1.排列字母 - 蓝桥云课 (lanqiao.cn)
#include <bits/stdc++.h>
using namespace std;
int main()
{
string str="WHERETHEREISAWILLTHEREISAWAY";
sort(str.begin(),str.end());
cout<<str<<endl;
return 0;
}
10,调试技巧
Dev-c++ 2:解决无法调试 & 调试步骤_dev c++ 不能调试的解决 法-优快云博客
蓝桥杯竞赛小白必学!开发环境:devC++调试方法_devc++蓝桥杯-优快云博客
二,工具函数
1.vector容器
#include <vector> //头文件
vector<int> a; //定义了一个int类型的vector容器a
vector<int> b[100]; //定义了一个int类型的vector容器b组
struct rec
{
···
};
vector<rec> c; //定义了一个rec类型的vector容器c
vector<int>::iterator it; //vector的迭代器,与指针类似
a.size() //返回实际长度(元素个数),O(1)复杂度
a.empty() //容器为空返回1,否则返回0,O(1)复杂度
a.clear() //把vector清空
a.begin() //返回指向第一个元素的迭代器,*a.begin()与a[0]作用相同
a.end() //越界访问,指向vector尾部,指向第n个元素再往后的边界
a.front() //返回第一个元素的值,等价于*a.begin和a[0]
a.back() //返回最后一个元素的值,等价于*--a.end()和a[size()-1]
a.push_back(x) //把元素x插入vector尾部
a.pop_back() //删除vector中最后一个元素
for ( vector<int>::iterator it=a.begin() ; it!=a.end() ; it++ )
cout<<*it<<endl;
for ( auto it=a.begin() ; it!=a.end() ; it++ )
cout<<*it<<endl;
//法一
for( int i=0;i<a.size();i++) cout<<a[i]<<endl;
//法二
2.queue容器
queue<string> myqueue;
queue<int> myqueue_int;
3.map容器
map<char, int> mymap1;
map<string, int> mymap2;
//1.看容量
int map.size();//查询map中有多少对元素
bool empty();// 查询map是否为空
//2.插入
map.insert(make_pair(key,value));
//或者
map.insert(pair<char, int>(key, value))
//或者
map[key]=value
//3.取值
map<int, string> map;
//如果map中没有关键字2233,使用[]取值会导致插入
//因此,下面语句不会报错,但会使得输出结果结果为空
cout<<map[2233]<<endl;
//但是使用使用at会进行关键字检查,因此下面语句会报错
map.at(2016) = "Bob";
//4.遍历
map<string, string>::iterator it;
for (it = mapSet.begin(); it != mapSet.end(); ++it)
{
cout << "key" << it->first << endl;
cout << "value" << it->second << endl;
}
//5.查找
m.count(key)://由于map不包含重复的key,因此m.count(key)取值为0,或者1,表示是否包含。
m.find(key)://返回迭代器,判断是否存在。
unordered_map不排序,内部实现为哈希
4.set容器
#include <bits/stdc++.h>
using namespace std;
// 1.set 的定义 set<数据类型> 变量名
set<int> intSet;
set<string> stringSet;
int main()
{
string s1="测试1";
string s2="测试2";
string s3="测试3";
//2. 插入操作
stringSet.insert(s3);
stringSet.insert(s1);
//5. 返回集合元素数量
printf("前2次插入操作完成后的元素数量为%d\n",stringSet.size());
stringSet.insert(s2);
printf("前3次插入操作完成后的元素数量为%d\n",stringSet.size());
//6.遍历整个集合,借助迭代器实现
//定义方式 容器类型< type> ::iterator name
set<string> ::iterator setStringIterator;
for(setStringIterator=stringSet.begin();setStringIterator!=stringSet.end();setStringIterator++)
cout<<*setStringIterator<<" ";
puts("");
//3. 删除操作
stringSet.erase(s3);
printf("删除操作完成后的元素数量为%d\n",stringSet.size());
for(setStringIterator=stringSet.begin();setStringIterator!=stringSet.end();setStringIterator++)
cout<<*setStringIterator<<" ";
puts("");
//4. 判断是否由此元素
if(stringSet.count(s2)!=0) cout<<"存在元素"<<s2<<endl;
}
5.stack容器
6.比较函数
7.使用队列:1.CLZ银行问题 - 蓝桥云课 (lanqiao.cn)
#include <bits/stdc++.h>
using namespace std;
queue<string> qv;
queue<string> qn;
int main()
{
int m;cin>>m;
while(m--)
{
string op;cin>>op;
if(op=="IN")
{
string name,ch;
cin>>name>>ch;
if(ch=="V")
{
qv.push(name);
}
else
{
qn.push(name);
}
}
else if(op=="OUT")
{
string ch;
cin>>ch;
if(ch=="V")
{
qv.pop();
}
else
{
qn.pop();
}
}
}
while(qv.size())
{
cout<<qv.front()<<endl;
qv.pop();
}
while(qn.size())
{
cout<<qn.front()<<endl;
qn.pop();
}
return 0;
}
8.使用set:
#include<bits/stdc++.h>
using namespace std;
set<string> ap;
int main()
{
int n;cin>>n;int flag=1;
while(n--)
{
string a;cin>>a;
if(ap.count(a))
{
cout<<a<<endl;
flag=0;
}
ap.insert(a);
}
if(flag)
{
cout<<"NO"<<endl;
}
return 0;
}
6
1fagas
dsafa32j
lkiuopybncv
hfgdjytr
cncxfg
sdhrest
9.使用map:1.快递分拣 - 蓝桥云课 (lanqiao.cn)
#include<bits/stdc++.h>
using namespace std;
map<string, vector<string>>mp;//分别放城市和单号
vector<string> citys;//用于存储出现过的城市名
int main()
{
int n;
cin >> n;
for (int i = 1;i <= n;i++)//循环读取单号和城市
{
string d, c;//单号,城市
cin >> d>> c;
if (!mp.count(c))//也可以写成 if(mp.find(c) == mp.end())--说明没有找到
{
citys.push_back(c);//如果这个城市之前没出现过就把他放在citys中
}
mp[c].push_back(d);//无论城市是否已经出现过都要讲单号添加到mp城市的后面
}//以上两步的顺序如果颠倒,那么if语句将始终无法运行
for (const auto& city : citys)//遍历citys中的每一个城市名
{
cout << city << ' ' << mp[city].size() << endl;//后者是mp中的键【city】后所对应的【值】的大小,即有几个单号
for (const auto& i : mp[city])//遍历每一个值--单号
{
cout << i << endl;
}
}
return 0;
}
三,枚举与双指针法
1.暴力枚举:第几个幸运数字 - 蓝桥云课 (lanqiao.cn)
#include <bits/stdc++.h>
using namespace std;
int main()
{
long long a=59084709587505;
int cnt=0;
for(int i=0;pow(3,i)<a;i++)
{
for(int j=0;pow(5,j)<a;j++)
{
for(int k=0;pow(7,k)<a;k++)
{
if(pow(3,i)*pow(5,j)*pow(7,k)<=a) cnt++;
}
}
}
cout<<cnt-1<<endl;
return 0;
}
2.组合型枚举93. 递归实现组合型枚举 - AcWing题库
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=30;//way[u]其中u最大为30,u是代表第几个数
int n,m;//从n中选择m个数
int way[N];
void dfs(int u,int start)
{
//额外补充:剪纸操作,例如当 4 占据第一个位置的时候实际上已经可以不用进行操作了
//公式:1.已经使用了u-1个数 距离n也就是数的上限还差 n-start+1
// 2.u-1+n-start+1<m 的时候就应该进行剪枝操作了
if(u+n-start<m) return;
if(u-1==m)//u-1代表已经选取了u-1个数恰好等于m的时候,就可以返回结果了
{
for(int i=1;i<=m;i++)
{
cout<<way[i]<<" ";
}
cout<<endl;
}
//进行递归操作
for(int i=start;i<=n;i++)
{
way[u]=i;
dfs(u+1,i+1);//下一个要使用的u就是u+1;start从i+1开始
way[u]=0;
}
}
int main()
{
scanf("%d%d",&n,&m);
dfs(1,1);//第二个也就是start记录了开始的数字
return 0;
}
//cnm
#include<bits/stdc++.h>
using namespace std;
vector<int> chosen;
int n,m;
void dfs(int u,int start)//第一个数代表当前处理的数
{
if(chosen.size()>m) return;//剪枝操作1
if(u+n-start<m) return;
if(u-1==m)
{
for(auto&p:chosen)
{
cout<<p<<" ";
}
cout<<endl;
}
for(int i=start;i<=n;i++)
{
chosen.push_back(i);
dfs(u+1,i+1);
chosen.pop_back();
}
}
int main()
{
cin>>n>>m;
dfs(1,1);//代表第一个位置放数,第二个位置是开始的数;
return 0;
}
//cnm vector精简版
#include<bits/stdc++.h>
using namespace std;
vector<int> chosen;
int n,m;
void dfs(int start)//
{
if(chosen.size()>m) return;//剪枝操作1
if(chosen.size()+(n-start+1)<m) return;
if(chosen.size()==m)
{
for(auto&p:chosen)
{
cout<<p<<" ";
}
cout<<endl;
}
for(int i=start;i<=n;i++)
{
chosen.push_back(i);
dfs(i+1);
chosen.pop_back();
}
}
int main()
{
cin>>n>>m;
dfs(1);//代表第一个位置放数,第二个位置是开始的数;
return 0;
}
3.排列形枚举94. 递归实现排列型枚举 - AcWing
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=9;
int n;
int st[N];//st代表状态,0表示还没有放数,1->n代表放了什么数
bool used[N];//true表示用过,false表示没用过
void dfs(int u)
{
if(u>n)
{
for(int i=1;i<=n;i++)
{
printf("%d ",st[i]);
}
puts("");
}
// 依次枚举每个数,即当前位置可以填哪些数
for(int i=1;i<=n;i++)
{
if(!used[i])
{
st[u]=i;
used[i]=true;
dfs(u+1);
st[u]=0;
used[i]=false;
}
}
}
int main()
{
cin>>n;
dfs(1);
return 0;
}
4.指数型枚举:dfs+二进制方法92. 递归实现指数型枚举 - AcWing题库
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=9;
int n;
int st[N];//st代表状态,1是说选中了,0是未选中状态,2是归位状态
void dfs(int u)
{
if (u > n)
{
for (int i = 1; i <= n; i ++ )
if (st[i] == 1)
{
printf("%d ", i);
}
puts("");
return;
}
st[u]=0;//不选的状态
dfs(u+1);
st[u]=2;//回复现场
st[u]=1;//选的状态
dfs(u+1);
st[u]=2;//回复现场
}
int main()
{
cin>>n;
dfs(1);
return 0;
}
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int a[20];
int main()
{
int n;cin>>n;
for(int i=0;i<n;i++)
{
a[i]=i+1;
}
for(int i=0;i<(1<<n);i++)//遍历位置的每个不同的情况
{
for(int j=0;j<n;j++)//一次情况的每一个位置
{
if(i&(1<<j))
{
cout<<a[j]<<" ";
}
}
cout<<endl;
}
return 0;
}
5.C++排列型枚举特殊方法:next_permutation:排列序数 - 蓝桥云课 (lanqiao.cn)
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;cin>>n;
string a="abc";
do{
cout<<a<<endl;
}while(next_permutation(a.begin(),a.end()));
return 0;
}
#include <bits/stdc++.h>
using namespace std;
int main()
{
string a;cin>>a;
string olds;olds=a;
int cnt=0;
sort(a.begin(),a.end());
do{
if(olds==a)
{
cout<<cnt<<endl;
break;
}
cnt++;
}while(next_permutation(a.begin(),a.end()));
return 0;
}
6.排列型枚举:火星人 - 蓝桥云课 (lanqiao.cn)
#include <bits/stdc++.h>
using namespace std;
int a[10011];
int main()
{
int n,m;cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=m;i++) next_permutation(a+1,a+n+1);
for(int i=1;i<=n;i++) cout<<a[i]<<" ";
return 0;
}
7,排列枚举:座次问题 - 蓝桥云课 (lanqiao.cn)
//排列dfs
#include<bits/stdc++.h>
using namespace std;
string a[13];
int main()
{
int n;cin>>n;
for(int i=0;i<n;i++)
{
cin>>a[i];
}
do{
for(int i=0;i<n;i++)
{
cout<<a[i]<<" ";
}
cout<<endl;
}while(next_permutation(a,a+n));
return 0;
}
//排列dfs
#include<bits/stdc++.h>
using namespace std;
string a[13];
string oou[13];
bool used[13];
int n;
void dfs(int u)
{
if(u==n)
{
for(int i=0;i<n;i++)
{
cout<<oou[i]<<" ";
}
cout<<endl;
}
for(int i=0;i<n;i++)
{
if(!used[i])
{
oou[u]=a[i];
used[i]=true;
dfs(u+1);
oou[u]="0";
used[i]=false;
}
}
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)
{
cin>>a[i];
}
dfs(0);//第一个位置是枚举数的个数,第二个数是枚举开始的数据a[0];
return 0;
}
8.组合枚举:公平抽签 - 蓝桥云课 (lanqiao.cn)
//组合型枚举
#include <iostream>
using namespace std;
int n,m;
string a[17];
string oou[17];
void dfs(int u,int start)
{
if(u==m)
{
for(int i=0;i<m;i++)
{
cout<<oou[i]<<" ";
}
cout<<endl;
}
for(int i=start;i<n;i++)
{
oou[u]=a[i];
dfs(u+1,i+1);
oou[u]="0";
}
}
int main()
{
cin>>n>>m;//从n中选m个
for(int i=0;i<n;i++)
{
cin>>a[i];
}
dfs(0,0);
return 0;
}
9.双指针:回文判定 - 蓝桥云课 (lanqiao.cn)
#include <iostream>
using namespace std;
int main()
{
string a;cin>>a;
int sizee=a.size();
for(int i=0,j=sizee-1;i<j;i++,j--)
{
if(a[i]!=a[j])
{
cout<<"N"<<endl;
return 0;
}
}
cout<<"Y"<<endl;
return 0;
}
#include <iostream>
using namespace std;
int main()
{
string a;cin>>a;
int sizee=a.size();
int flag=1;
for(int i=0,j=sizee-1;i<j;i++,j--)
{
if(a[i]!=a[j])
{
flag=0;
cout<<"N"<<endl;
}
}
if(flag) cout<<"Y"<<endl;
return 0;
}
10.双指针:互补的整数对 - 蓝桥云课 (lanqiao.cn)
#include <bits/stdc++.h>
using namespace std;
int a[100010];
int main()
{
int n,s;cin>>n>>s;
for(int i=0;i<n;i++)
{
cin>>a[i];
}
sort(a,a+n);
int res=0;
int i=0,j=n-1;
while(i<j)
{
int sum=a[i]+a[j];
if(sum>s)
{
j--;
}
else if(sum<s)
{
i++;
}
else
{
res++;
i++,j--;
}a
}
cout<<res<<endl;
return 0;
}
11.双指针:1.美丽的区间 - 蓝桥云课 (lanqiao.cn)
#include <iostream>
using namespace std;
int a[100040],sum[100040];
int main()
{
int n,s;cin>>n>>s;
for(int i=1;i<=n;i++)
{
cin>>a[i];
sum[i]+=sum[i-1]+a[i];
}
int res=0x7f7f7f7f;
int flag=0;
for(int i=1,j=1;j<=n;)
{
if(sum[j]-sum[i-1]<s)
{
j++;
}
if(sum[j]-sum[i-1]>=s)
{
flag=1;
res=min(res,j-i+1);
i++;
}
}
if(flag==0) cout<<0<<endl;
else cout<<res<<endl;
return 0;
}
四,递归与递推
1.斐波那契数列的递归与递推和记忆化
递推表达式:f(n)=f(n-1)+f(n-2)
int fib[25];
int main()
{
fib[1] = fib[2] = 1;
for (int i = 3; i <= 20; i++)
{
fib[i] = fib[i - 1] + fib[i - 2];
}
cout << fib[20] << endl;
return 0;
}
递归:
int cnt = 0;
int dfs_fib(int n)
{
cnt++;
if (n == 1 || n == 2) return 1;
else return dfs_fib(n - 1) + dfs_fib(n - 2);
}
int main()
{
cout << dfs_fib(20) << endl;//6765
cout <<"递归进行了几次:" << cnt;//递归进行了几次:13529
return 0;
}
记忆化递归:减少递归的次数
int cnt = 0;
int dat[25];
int dfs_fib(int n)
{
cnt++;
if (dat[n] != 0) return dat[n];
if (n == 1 || n == 2) return 1;
dat[n]=dfs_fib(n - 1) + dfs_fib(n - 2);
return dat[n];
}
int main()
{
cout << dfs_fib(20) << endl;//6765
cout <<"递归进行了几次:" << cnt;//递归进行了几次:37
return 0;
}
2.递推:数字三角形:数字三角形 - 蓝桥云课 (lanqiao.cn)
#include<bits/stdc++.h>
using namespace std;
int n;//有多少层
int a[111][111];//每行每列有多少
int main()
{
//输入数据
cin>>n;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=i;j++)
{
cin>>a[i][j];
}
}
//从下向上的向下选择
for(int i=n-1;i>=1;i--)
{
for(int j=1;j<=i;j++)
{
if(a[i+1][j]<a[i+1][j+1])
a[i][j]+=a[i+1][j+1];
else
a[i][j]+=a[i+1][j];
}
}
cout<<a[1][1]<<endl;
return 0;
}
3.42点问题:42点问题 - 蓝桥云课 (lanqiao.cn)
//借助vector<>容器的做法
#include<bits/stdc++.h>
using namespace std;
int a[6];
int main()
{
//数据的输入
for(int i=0;i<6;i++)
{
char c;cin>>c;
if(c=='A')
{
a[i]=1;
}
else if(c=='K')
{
a[i]=13;
}
else if(c=='Q')
{
a[i]=12;
}
else if(c=='J')
{
a[i]=11;
}
else
{
a[i]=c-'0';
}
}
//数据的处理
vector<int> ans[6];
ans[0].push_back(a[0]);
for(int i=1;i<=5;i++)
{
for(int j=0;j<ans[i-1].size();j++)
{
ans[i].push_back(a[i-1][j]+a[i]);
ans[i].push_back(a[i-1][j]-a[i]);
ans[i].push_back(a[i-1][j]*a[i]);
ans[i].push_back(int(a[i-1][j]/a[i]));
}
}
int flag=0;
for(int i=0;i<ans[5].size();i++)
{
if(a[5][i]==42)
{
flag=1;
}
}
if(flag) cout<<"YES"<<endl;
esle cout<<"NO"<<endl;
return 0;
}
错误:ans和a混乱
//借助vector<>容器的做法
#include<bits/stdc++.h>
using namespace std;
int a[6];
int main()
{
//数据的输入
for(int i=0;i<6;i++)
{
char c;cin>>c;
if(c=='A')
{
a[i]=1;
}
else if(c=='K')
{
a[i]=13;
}
else if(c=='Q')
{
a[i]=12;
}
else if(c=='J')
{
a[i]=11;
}
else
{
a[i]=c-'0';
}
}
//数据的处理
vector<int> ans[6];
ans[0].push_back(a[0]);
for(int i=1;i<=5;i++)
{
for(int j=0;j<int(ans[i-1].size());j++)
{
ans[i].push_back(ans[i-1][j]+a[i]);
ans[i].push_back(ans[i-1][j]-a[i]);
ans[i].push_back(ans[i-1][j]*a[i]);
ans[i].push_back(int(ans[i-1][j]/a[i]));
}
}
int flag=0;
for(int i=0;i<int(ans[5].size());i++)
{
if(ans[5][i]==42)
{
flag=1;
}
}
if(flag) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
return 0;
}
//dfs
#include<bits/stdc++.h>
using namespace std;
int a[6];
int flag = 0;
char opt[6];
char all[4] = { '+','-','*','/' };
//运算函数
int calculate(int num1, int num2, char op)
{
switch (op)
{
case '+':
return num1 + num2;
case '-':
return num1 - num2;
case '*':
return num1 * num2;
case '/':
return num1 / num2;
}
}
void dfs(int u)
{
if (u == 5)
{
if (42 == calculate(calculate(calculate(calculate(calculate(a[0], a[1], opt[0]), a[2], opt[1]), a[3], opt[2]), a[4], opt[3]), a[5], opt[4]))
{
flag = 1;
return;
}
return;
}
for (int i = 0; i < 4; i++)
{
opt[u] = all[i];
dfs(u + 1);
opt[u] = '%';//回复现场
}
}
int main()
{
//数据的输入
for (int i = 0; i < 6; i++)
{
char c; cin >> c;
if (c == 'A')
{
a[i] = 1;
}
else if (c == 'K')
{
a[i] = 13;
}
else if (c == 'Q')
{
a[i] = 12;
}
else if (c == 'J')
{
a[i] = 11;
}
else
{
a[i] = c - '0';
}
}
dfs(0);//代表第0个位置
if (flag) cout << "YES" << endl;
if (!flag) cout << "NO" << endl;
return 0;
}
4.模拟递归递推:数的计算:数的计算 - 蓝桥云课 (lanqiao.cn)
#include<bits/stdc++.h>
using namespace std;
int f[10010];
int main()
{
int n;cin>>n;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=i/2;j++)
{
f[i]+=f[j];
}
f[i]+=1;
}
cout<<f[n]<<endl;
return 0;
}
#include<bits/stdc++.h>
using namespace std;
int res=1;
void dfs(int n)
{
if(n==1) return ;
for(int i=1;i<=n/2;i++)
{
res++;
dfs(i);
}
}
int main()
{
int n;cin>>n;
dfs(n);
cout<<res<<endl;
return 0;
}
5.数字dp递推:数的划分:数的划分 - 蓝桥云课 (lanqiao.cn)
#include<bits/stdc++.h>
using namespace std;
int shuweidp[202][8];
int main()
{
int n,k;cin>>n>>k;
shuweidp[0][0]=1;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=k;j++)
{
if(i>=j) shuweidp[i][j]=shuweidp[i-j][j]+shuweidp[i-1][j-1];
}
}
cout<<shuweidp[n][k]<<endl;
return 0;
}
6.简单:天干地支:天干地支 - 蓝桥云课 (lanqiao.cn)
#include <iostream>
using namespace std;
string tiangan[10]={"jia","yi","bing","ding","wu","ji","geng","xin","ren","gui"};
string dizhi[12]={"zi","chou","yin","mao","chen","si","wu","wei","shen","you","xu","hai"};
int main()
{
//天干10年一轮,地支12一轮
int n;cin>>n;
cout<<tiangan[(n%10+6)%10]<<dizhi[(n%12+8)%12]<<endl;
return 0;
}
五,搜索算法
0.dfs和bfs的基本范式
int check(参数)
{
}
bool pd(参数)
{
}
void dfs(int step)
{
判断check()
{
不在边界内,即回溯
}
尝试每一种可能
{
满足pd条件
标记
继续下一步dfs(step+1)
恢复初始状态(回溯的时候要用到)
}
}
int check(参数)
{
if(满足条件)
return 1;
return 0;
}
bool pd(参数){
相应操作
}
void bfs()
{
1. 把根节点放入队列尾端
2. 每次从队列中取出一个节点
3. Check 判断是不是答案,如果是结束算法 return;
4. 把当前取出的节点扩展,如果扩展后的节点经Pd()后符合要求,就放入队列,不符合就不放。
5. 转到步骤2,循环执行
}
如果所有节点被扩展完了,没有找到答案就无解。
bfs解题流程:
1. 初始状态入队
2. while(队列不是空的)
2.1 取出队头元素放入t,并弹出队头
2.2 for(扩展队列) 经过判重,将新节点插入队尾
1.dfs:1.N皇后问题 - 蓝桥云课 (lanqiao.cn)
#include <bits/stdc++.h>
using namespace std;
int x[15]={0};//这个用来表示列不用关系行,因为我们处理时将每行都处理出来了
int n,ans;
int pd(int a)
{
for(int i=1;i<a;i++)
{
//在对角线上
if(abs(a-i)==abs(x[a]-x[i]))
{
return 0;
}
//在同一列上
else if(x[i]==x[a])
{
return 0;
}
}
return 1;
}
void dfs(int a)
{
//1.判断边界情况也就是超出的情况
if(a>n)
{
ans++;
return;
}
//2.尝试每一种可能
for(int i=1;i<=n;i++)
{
x[a]=i;//第a个n皇后放的列数
if(pd(a))//判断这一步能否成立
{
dfs(a+1);//可以的话就放置下一个皇后
}
else
continue;//不可以的话跳到下一个循环
}
}
int main()
{
cin>>n;
dfs(1);//放置第一个n皇后
cout<<ans<<endl;
return 0;
}
2.dfs:1.路径之谜 - 蓝桥云课 (lanqiao.cn)
#include <bits/stdc++.h>
using namespace std;
int row[25],column[25];
bool flag[25][25];
int n;
typedef pair<int,int> PII;
vector<PII> res;
int dx[4]={0,0,-1,1},dy[4]={-1,1,0,0};
bool check(int x,int y)
{
if(x==n && y==n)
{
for(int i=1;i<=n;i++)
{
if(column[i]!=0) return false;
if(row[i]!=0) return false;
}
return true;
}
else return false;
}
bool pd(int x,int y)//看看是否加入
{
if(flag[x][y]==1 || x<1 || x>n || y<1 ||y>n ||column[x]<=0 ||row[y]<=0) return 0;
else return 1;
}
void dfs(int x,int y)
{
if(check(x,y))//判断是否结束
{
for(int i=0;i<res.size();i++)
{
int x1=res[i].first;
int y1=res[i].second;
int sum=n*(x1-1)+y1-1;
cout<<sum<<" ";
}
cout<<endl;
return;
}
else
{
for(int i=0;i<4;i++)
{
int xt=dx[i]+x;
int yt=dy[i]+y;
if(!pd(xt,yt)) continue;//判断不成立,遍历下一个i
else
{
flag[xt][yt]=true;
column[xt]--;
row[yt]--;
res.push_back({xt,yt});
//回复现场
res.pop_back();
flag[xt][yt]=false;
column[xt]++;
row[yt]++;
}
}
}
}
int main()
{
cin>>n;//表示n*n
for(int i=1;i<=n;i++)
{
cin>>row[i];
}
for(int j=1;j<=n;j++)
{
cin>>column[j];
}
row[1]--;
column[1]--;
res.push_back({1,1});
dfs(1,1);
return 0;
}
#include <bits/stdc++.h>
using namespace std;
int row[30],column[30];
bool flag[30][30];
int n;
typedef pair<int,int> PII;
vector<PII> res;
int dx[4]={0,0,-1,1},dy[4]={-1,1,0,0};
bool check(int x,int y)
{
if(x==n && y==n)
{
for(int i=1;i<=n;i++)
{
if(column[i]!=0) return false;
if(row[i]!=0) return false;
}
return true;
}
else return false;
}
bool pd(int x,int y)//看看是否加入
{
if(flag[x][y]==1 || x<1 || x>n || y<1 ||y>n ||column[x]<=0 ||row[y]<=0) return 0;
else return 1;
}
void dfs(int x,int y)
{
if(check(x,y))//判断是否结束
{
for(int i=0;i<res.size();i++)
{
int x1=res[i].first;
int y1=res[i].second;
int sum=n*(x1-1)+y1-1;
cout<<sum<<" ";
}
cout<<endl;
return;
}
else
{
for(int i=0;i<4;i++)
{
int xt=dx[i]+x;
int yt=dy[i]+y;
if(!pd(xt,yt)) continue;//判断不成立,遍历下一个i
else
{
flag[xt][yt]=true;
column[xt]--;
row[yt]--;
res.push_back({xt,yt});
dfs(xt,yt);
//回复现场
res.pop_back();
flag[xt][yt]=false;
column[xt]++;
row[yt]++;
}
}
}
}
int main()
{
cin>>n;//表示n*n
for(int i=1;i<=n;i++)
{
cin>>row[i];
}
for(int j=1;j<=n;j++)
{
cin>>column[j];
}
flag[1][1]=true;
row[1]--;
column[1]--;
res.push_back({1,1});
dfs(1,1);
return 0;
}
3.bfs:1.长草 - 蓝桥云课 (lanqiao.cn)
#include <bits/stdc++.h>
using namespace std;
const int N=1050;
char aa[N][N];
int n,m,k;
typedef pair<int,int> PII;
queue<PII> q;
int cnt=0;
int dx[4]={1,-1,0,0},dy[4]={0,0,1,-1};
int len;
void bfs()
{
//1. 初始状态入队
//2. while(队列不是空的)
while(q.size()&&k>0)
{
//2.1 取出队头元素放入t,并弹出队头
PII t=q.front();
q.pop();
len--;
//2.2 for(扩展队列) 经过判重,将新节点插入队尾
for(int i=0;i<4;i++)
{
int a=t.first+dx[i],b=t.second+dy[i];
if(a<=0||a>m||b<=0||b>n||aa[a][b]=='g') continue;
aa[a][b]='g';
q.push({a,b});
}
if(len==0)
{
k--;
len=q.size();
}
}
}
int main()
{
//数据输入
cin>>m>>n;
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
{
cin>>aa[i][j];
if(aa[i][j]=='g') q.push({i,j});
}
}
cin>>k;
//数据处理
len=q.size();//记录k=0时有多少个节点
bfs();
//输出
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
{
cout<<aa[i][j];
}
cout<<endl;
}
return 0;
}
4.bfs:1.走迷宫 - 蓝桥云课 (lanqiao.cn)献给阿尔吉侬的花束
#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
queue<PII> q;
int n,m;
PII start,endd;
int dx[4]={1,-1,0,0},dy[4]={0,0,1,-1};
int maap[110][111];
int dist[110][111];
bool used[110][111];//不可以往回走
int bfs(PII start,PII endd)
{
q.push(start);
dist[1][1]=0;
used[1][1]=true;
while(q.size())
{
PII t=q.front();
q.pop();
for(int i=0;i<4;i++)
{
int a=t.first+dx[i],b=t.second+dy[i];
if(a<1||a>n||b<1||b>m||maap[a][b]==0||used[a][b]) continue;
q.push({a,b});
dist[a][b]=1+dist[t.first][t.second];
used[a][b]=true;
if(a==endd.first&&b==endd.second)
{
return dist[a][b];
}
}
}
return -1;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin>>maap[i][j];
}
}
int x1,y1,x2,y2;cin>>x1>>y1>>x2>>y2;
start={x1,y1},endd={x2,y2};
int distance=bfs(start,endd);
if(distance!=-1) cout<<distance<<endl;
else cout<<"-1"<<endl;
return 0;
}
5.bfs:1.迷宫 - 蓝桥云课 (lanqiao.cn)
#include<bits/stdc++.h>
using namespace std;
string maze[30]= {//30行 0->29 50列 0->49
"01010101001011001001010110010110100100001000101010",
"00001000100000101010010000100000001001100110100101",
"01111011010010001000001101001011100011000000010000",
"01000000001010100011010000101000001010101011001011",
"00011111000000101000010010100010100000101100000000",
"11001000110101000010101100011010011010101011110111",
"00011011010101001001001010000001000101001110000000",
"10100000101000100110101010111110011000010000111010",
"00111000001010100001100010000001000101001100001001",
"11000110100001110010001001010101010101010001101000",
"00010000100100000101001010101110100010101010000101",
"11100100101001001000010000010101010100100100010100",
"00000010000000101011001111010001100000101010100011",
"10101010011100001000011000010110011110110100001000",
"10101010100001101010100101000010100000111011101001",
"10000000101100010000101100101101001011100000000100",
"10101001000000010100100001000100000100011110101001",
"00101001010101101001010100011010101101110000110101",
"11001010000100001100000010100101000001000111000010",
"00001000110000110101101000000100101001001000011101",
"10100101000101000000001110110010110101101010100001",
"00101000010000110101010000100010001001000100010101",
"10100001000110010001000010101001010101011111010010",
"00000100101000000110010100101001000001000000000010",
"11010000001001110111001001000011101001011011101000",
"00000110100010001000100000001000011101000000110011",
"10101000101000100010001111100010101001010000001000",
"10000010100101001010110000000100101010001011101000",
"00111100001000010000000110111000000001000000001011",
"10000001100111010111010001000110111010101101111000"};
struct node{
int x,y,d;
char pos;
};
node father[1562][1562];//当前节点的父节点;
bool vis[1562][1562];
int dx[4]={1,0,0,-1};
int dy[4]={0,-1,1,0};
void dfs(int x,int y)
{
if(x==0&&y==0) return;
else dfs(father[x][y].x,father[x][y].y);
cout<<father[x][y].pos;//第一个输出的就是x=0,y=0的下一个情况
}
void bfs(int x,int y)
{
queue<node> q;
q.push({x,y,0});
vis[x][y]=true;
while(q.size())
{
auto t=q.front();
q.pop();
for(int i=0;i<4;i++)//按照 下 左 右 上 的字典序来走路
{
int a=t.x+dx[i],b=t.y+dy[i];
if(a<0||b<0||a>29||b>49||vis[a][b]||maze[a][b]=='1') continue;
q.push({a,b,t.d+1});
vis[a][b]=1;
//存储父节点的坐标
father[a][b].x=t.x;
father[a][b].y=t.y;
if(i==0) father[a][b].pos='D';
else if(i==1) father[a][b].pos='L';
else if(i==2) father[a][b].pos='R';
else if(i==3) father[a][b].pos='U';
}
}
}
int main()
{
bfs(0,0);
dfs(29,49);
}
六,差分与前缀和
1.大学里的树木要打药 - 蓝桥云课 (lanqiao.cn)
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,c;cin>>n>>c;
int ss=0;
for(int i=0;i<c;i++)
{
int l,r,m;cin>>l>>r>>m;
ss+=(r-l+1)*m;
}
cout<<ss<<endl;
return 0;
}
#include<bits/stdc++.h>
using namespace std;
int b[1000300];
int main()
{
int n,c;cin>>n>>c;
while(c--)
{
int l,r,value;cin>>l>>r>>value;
b[l+1]+=value;
b[r+1+1]-=value;
}
int sum=0;
for(int i=1;i<=n;i++)
{
b[i]=b[i]+b[i-1];
sum+=b[i];
}
cout<<sum<<endl;
return 0;
}
2.大学里的树木要维护 - 蓝桥云课 (lanqiao.cn)
#include<bits/stdc++.h>
using namespace std;
int sum[30000];
int main()
{
int n,q;cin>>n>>q;
for(int i=1;i<=n;i++)
{
cin>>sum[i];
sum[i]=sum[i-1]+sum[i];
}
while(q--)
{
int l,r;cin>>l>>r;
cout<<sum[r]-sum[l-1]<<endl;;
}
return 0;
}
七,构造
我理解的构造就是说找数学规律
1.找规律(不看)
#include<bits/stdc++.h>
using namespace std;
int x,y,z,n;
int main()
{
cin>>n;
cout<<n*2<<" "<<n*3<<" "<<n*6<<endl;
return 0;
}
2.简答数论(找最大公约数)1246. 等差数列 - AcWing题库
#include<bits/stdc++.h>
using namespace std;
const int N=100010;
int a[N];
int gcd(int a,int b)
{
return b ? gcd(b,a % b) : a;
}
int main()
{
int n;cin>>n;
for(int i=0;i<n;i++)
{
cin>>a[i];
}
sort(a,a+n);
//找d
int d=0;
for(int i=1;i<n;i++) d=gcd(d,a[i]-a[i-1]);
//输出答案
if (!d) printf("%d\n", n);
else printf("%d\n", (a[n - 1] - a[0]) / d + 1);
return 0;
}
3.思维题(不看)
八,并查集
代码思想:
第三个先别看:没理解
代码板子:
1.朴素并查集
const int N = 200010;
int p[N];
int find(int x)//已经带了路径压缩
{
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
//初始化
for (int i = 1; i <= n; i++)
{
p[i] = i;
}
//合并a和b所在的集合
p[find(a)] = find(b);
2.维护size的并查集 and 启发式合并维护size并查集
const int N = 200010;
int p[N],sz[N];
int find(int x)//已经带了路径压缩
{
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
//初始化
for (int i = 1; i <= n; i++)
{
p[i] = i;
sz[i]=1;
}
//合并a和b所在的集合
p[find(a)] = find(b);
sz[find(b)]+=sz[find(a)];
const int N = 200010;
int p[N],sz[N];
int find(int x)//已经带了路径压缩
{
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
//初始化
for (int i = 1; i <= n; i++)
{
p[i] = i;
sz[i]=1;
}
//所谓启发式合并:合并a和b所在的集合
//让小的集合去合并到大的集合
void merge(int a,int b)//让a作为小的合并到大的b上
{
a=find(a);b=find(b);
if(a!=b)
{
if(sz[a]>sz[b])
swap(a,b);
sz[find(b)]+=sz[find(a)];
p[find(a)]=find(b);
//sz[find(a)]+=sz[find(b)];
//p[find(b)]=find(a);
}
}
3.维护到祖宗节点距离的并查集
int p[N],d[N];
//p[]存储每个点的祖宗节点,d[x]存储x到p[x]的距离
//返回x的祖宗节点
int find(int x)
{
if(p[x]!=x)
{
int root=find(p[x]);
d[x]+=d[p[x]];
p[x]=root;
}
}
for(int i=1;i<=n;i++)
{
p[i]=i;
d[i]=0;
}
//合并连个集合
p[find(a)]=find(b);
d[find(a)]=distance;//根据具体问题,初始化find(a)的偏移量
例题:
1.836. 合并集合 - AcWing题库
#include<bits/stdc++.h>
using namespace std;
int n,m;
int fa[100033],siz[100033];
struct undoobject
{
int pos,val;
undoobject(int p,int v)
{
pos=p;
val=v;
}
};
stack<undoobject> undosize,undofa;
void init()
{
for(int i=1;i<=n;i++)
{
fa[i]=i;
siz[i]=i;
}
while(!undosize.empty()) undosize.pop();
while(!undofa.empty()) undofa.pop();
}
int find(int x)
{
if(fa[x]==x) return x;
return find(fa[x]);
}
//操作1
void merge(int u,int v)
{
int x=find(u),y=find(v);
if(x==y) return ;//在一个集合无需合并
if(siz[x]<siz[y]) swap(x,y);//将y和并到x上
undosize.push(undoobject(x,siz[x]));
siz[x]+=siz[y];
undofa.push(undoobject(y,fa[y]));
fa[y]=x;
}
//操作2
bool chaxun(int x,int y)
{
x=find(x),y=find(y);
if(x==y) return true;
else return false;
}
//操作3
void undo()
{
siz[undosize.top().pos]=undosize.top().val;
undosize.pop();
fa[undofa.top().pos]=undofa.top().val;
undofa.pop();
}
int main()
{
cin>>n>>m;
init();
while(m--)
{
char q;cin>>q;
if(q=='M')
{
int u,v;cin>>u>>v;
merge(u,v);
}
else if(q=='Q')
{
int u,v;cin>>u>>v;
if(chaxun(u,v)) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
else
{
undo();
}
}
return 0;
}
2.带权重的并查集240. 食物链 - AcWing题库
总体框架
疑问详解
参考文档:
AcWing 240. 食物链—数组d的真正含义以及find()函数调用过程 - AcWing
ac码
#include <iostream>
using namespace std;
const int N = 1e5 + 10;
int n, m;
int p[N], d[N]; //p[]寻找祖宗节点,d[]求到祖宗节点的距离
int find(int x)
{
if (p[x] != x)
{
int t = find(p[x]); // u暂时存一下p[x]根节点,辅助变量
d[x] += d[p[x]]; // 更新距离
p[x] = t;
}
return p[x];
}
// 不行,因为这个路径的长度(高度),是需要自上而下加起来的,从根节点往下走
// 所以要先调用递归
// int find(int x)
// {
// if (p[x] != x)
// {
// d[x] += d[p[x]]; // 更新距离
// p[x] = find(p[x]);
// }
// return p[x];
// }
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i ++ ) p[i] = i;
int res = 0;//记录错误数
while (m -- )
{
int t, x, y;
scanf("%d%d%d", &t, &x, &y);
if (x > n || y > n) res ++ ; // 当前的话中X或Y比N大,是假话
else
{
int px = find(x), py = find(y); // 查找根节点
if (t == 1) // 判断是否同类
{
if (px == py) { // 若 x 与 y 在同一个集合中
if ((d[x] - d[y]) % 3) res ++ ; // 两数到根节点距离之差的模不为 0,说明不是同一类,是假话
// 其中 (d[x] - d[y]) % 3 不可写为 d[x] % 3 != d[y] % 3
// 因为 d[x], d[y] 可能为负数(一正一负),可改做 (d[x] % 3 + 3) % 3 != (d[y] % 3 + 3) % 3
// 负数 mod 正数为负数
} else { // 则 x 与 y 不在同一个集合中
p[px] = py; // x 所在集合 合并到 y 所在集合
d[px] = d[y] - d[x];
// d[x] 的距离为什么不更新?
// 只是暂时不更新,在调用 find 时再更新
}
}
else // X 是否吃 Y
{
if (px == py) { // 若 x 与 y 在同一个集合中
// 若 X 吃 Y,则 d[x] 比 d[y] 大 1
if ((d[x] - d[y] - 1) % 3) res ++ ; // 若距离之差 - 1 的模不为 0,说明吃不掉,是假话
} else { // 则 x 与 y 不在同一个集合中
p[px] = py;
// (d[x] - d[y] - 1) % 3 == 0
// d[x] + d[px] - 1 = d[y] 则:
d[px] = d[y] + 1 - d[x];
}
}
}
}
printf("%d\n", res);
return 0;
}
#include<bits/stdc++.h>
using namespace std;
int n,k;
int p[50022],d[50022];
void init()
{
for(int i=1;i<=n;i++)
{
p[i]=i;
d[i]=0;
}
}
int find(int x)
{
if(p[x]!=x)
{
int u=find(p[x]);
d[x] += d[p[x]];
p[x]=u;
}
return p[x];
}
int main()
{
cin>>n>>k;
init();
int res=0;
while(k--)
{
int t,x,y;cin>>t>>x>>y;
if(x>n||y>n) res++;//直接不合理
else
{
int px=find(x),py=find(y);
if(t==1)
{
if((px==py)&&(d[x]-d[y])%3!=0)//先看看是否已经出现过了,这是出现过的情况
{
res++;
}
else if(px!=py)
{
p[px]=py;
d[px]=d[y]-d[x];
}
}
else if(t==2)
{
if((px==py)&&(d[x]-d[y]-1)%3!=0)//先看看是否已经出现过了,这是出现过的情况
{
res++;
}
else if(px!=py)
{
p[px]=py;
d[px]=d[y]+1-d[x];
}
}
}
}
cout<<res<<endl;
return 0;
}
3.合根植物 - 蓝桥云课 (lanqiao.cn)
#include <bits/stdc++.h>
using namespace std;
const int N=1000020;
int p[N];
int m,n,k;
void init()
{
for(int i=1;i<=N;i++)
{
p[i]=i;
}
}
int find(int x)
{
if(p[x]!=x) p[x]=find(p[x]);
return p[x];
}
void merge(int a,int b)
{
p[find(a)]=find(b);
}
int main()
{
init();
cin>>n>>m>>k;
init();
for(int i=1;i<=k;i++)
{
int a,b;cin>>a>>b;
merge(a,b);
}
int ans=0;
for(int i=1;i<=m*n;i++)
{
if(p[i]==i) ans++;
}
cout<<ans<<endl;
return 0;
}
#include <bits/stdc++.h>
using namespace std;
const int N=1000020;
int p[N];
int siz[N];
int m,n,k;
void init()
{
for(int i=1;i<=N;i++)
{
p[i]=i;
siz[i]=1;
}
}
int find(int x)
{
if(p[x]!=x) p[x]=find(p[x]);
return p[x];
}
void merge(int a,int b)
{
a=find(a);
b=find(b);
if(a!=b)
{
if(siz[a]>siz[b]) swap(a,b); //让size小的a合到b上
siz[find(b)]+=siz[find(a)];//一定要记住先写siz
p[find(a)]=find(b);
}
}
int main()
{
init();
cin>>n>>m>>k;
init();
for(int i=1;i<=k;i++)
{
int a,b;cin>>a>>b;
merge(a,b);
}
int ans=0;
for(int i=1;i<=m*n;i++)
{
if(p[i]==i) ans++;
}
cout<<ans<<endl;
cout<<siz[19];
return 0;
}
#include <bits/stdc++.h>
using namespace std;
const int N=1000020;
int p[N];
int rk[N];
int m,n,k;
void init()
{
for(int i=1;i<=N;i++)
{
p[i]=i;
rk[i]=1;//这里可描述权重,边的大小
}
}
int find(int x)
{
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
void merge(int a,int b)
{
a=find(a);
b=find(b);
if(a!=b)
{
if(rk[a]>rk[b]) swap(a,b); //让rk小的a合到b上
p[a]=b;
if(rk[a]==rk[b]) rk[b]++;
//这里我解释一下我的疑惑为什么两个不相等的rk就不用变呢?
//因为小的合到大的那么大的层数肯定还是不变
}
}
int main()
{
init();
cin>>n>>m>>k;
init();
for(int i=1;i<=k;i++)
{
int a,b;cin>>a>>b;
merge(a,b);
}
int ans=0;
for(int i=1;i<=m*n;i++)
{
if(p[i]==i) ans++;
}
cout<<ans<<endl;
return 0;
}
4.修改数组 - 蓝桥云课 (lanqiao.cn)
#include <iostream>
using namespace std;
int p[1000040];
int n;
void init()
{
for(int i=1;i<=1000040;i++)
{
p[i]=i;
}
}
int find(int x)
{
if(p[x]!=x) p[x]=find(p[x]);
return p[x];
}
void merge(int a,int b)
{
p[find(a)]=find(b);
}
int main()
{
//显然我想写双指针
//但是这个题一定可以用不带路径压缩的并查集来查找~
cin>>n;
init();
while(n--)
{
int t;
cin>>t;
t=find(t);
cout<<t<<" ";
merge(t,t+1);
}
return 0;
}
5.可撤销并查集
参考文档:【No.12】蓝桥杯可撤销并查集|查找|合并|撤销(C++)_在蓝桥王国中有个城市,王国经常会发生地震,会导致道路塌方,好在王国科技水平比较-优快云博客
int n, q;
int fa[20000005], sz[2000005];
struct UndoObject
{
int pos, val;
UndoObject(int p, int v)
{
pos = p;
val = v;
}
};
stack<UndoObject> undo_sz, undo_fa;
//undo_sz,记录树的大小:记录每次连接操作的 较大的节点 和 较大的节点的大小
//undo_fa,记录它的父亲是谁:记录每次连接操作的 较小的节点的 原本的父节点
void init(int n)
{
for (int i = 1; i <= n; i ++)
fa[i] = i, sz[i] = 1; //一棵点,就是自己
while (!undo_sz.empty())
undo_sz.pop(); //清除之前的栈的内容
while (!undo_fa.empty())
undo_fa.pop(); //清除之前的栈的内容
}
//
int find (int x)
{
if (x == fa[x])
return x;
return find(fa[x]);
}
void merge(int u,int v)
{
int x=find(u),y=find(v);
if(x==y) return;
if(siz[x]<siz[y])swap(x,y);//将y节点合到x节点上
//把原值放入,存完以后改掉
undo_sz.push(UndoObject(x,siz[x]))//这个是保留的源节点的大小信息
siz[x]+=siz[y];
//
undo_fa.push(UndoObject(y,fa[y]))//这个保留了下面的操作
fa[y]=x;
}
void undo()
{
fa[undo_fa.top().pos]=undo_fa.top().val;
undo_fa.pop();//这一次撤销操作完成
siz[undo_sz.top().pos]=undo_sz.top().val;//这个是保留的
undo_sz.pop();
}
把这道题:改一下命题写成操作三为撤销:836. 合并集合 - AcWing题库
#include<bits/stdc++.h>
using namespace std;
int n,m;
int fa[100033],siz[100033];
struct undoobject
{
int pos,val;
undoobject(int p,int v)
{
pos=p;
val=v;
}
};
stack<undoobject> undosize,undofa;
void init()
{
for(int i=1;i<=n;i++)
{
fa[i]=i;
siz[i]=i;
}
while(!undosize.empty()) undosize.pop();
while(!undofa.empty()) undofa.pop();
}
int find(int x)
{
if(fa[x]==x) return x;
return find(fa[x]);
}
//操作1
void merge(int u,int v)
{
int x=find(u),y=find(v);
if(x==y) return ;//在一个集合无需合并
if(siz[x]<siz[y]) swap(x,y);//将y和并到x上
undosize.push(undoobject(x,siz[x]));
siz[x]+=siz[y];
undofa.push(undoobject(y,fa[y]));
fa[y]=x;
}
//操作2
bool chaxun(int x,int y)
{
x=find(x),y=find(y);
if(x==y) return true;
else return false;
}
//操作3
void undo()
{
siz[undosize.top().pos]=undosize.top().val;
undosize.pop();
fa[undofa.top().pos]=undofa.top().val;
undofa.pop();
}
int main()
{
cin>>n>>m;
init();
while(m--)
{
char q;cin>>q;
if(q=='M')
{
int u,v;cin>>u>>v;
merge(u,v);
}
else if(q=='Q')
{
int u,v;cin>>u>>v;
if(chaxun(u,v)) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
else
{
undo();
}
}
return 0;
}
九,二分法
整数二分
模板:789. 数的范围 - AcWing题库
#include<iostream>
#include<vector>
using namespace std;
vector<int> tmp;
int SL(int l,int r,int query)
{
while(l<r)
{
int mid=l+r>>1;
if(tmp[mid]>=query) r=mid;//if(绿) 口诀:后r美加一
else l=mid+1;
}
return l;
}
int SR(int l,int r,int query)
{
while(l<r)
{
int mid=l+r+1>>1;
if(tmp[mid]<=query) l=mid;
else r=mid-1;
}
return l;
}
int main()
{
int n,q;cin>>n>>q;
for(int i=0;i<n;i++)
{
int a;cin>>a;
tmp.push_back(a);
}
for(int i=0;i<q;i++)
{
//思考一下二段性,利用红绿线段进行思考
//找sl就是找绿线段,也就是后面的那个
//找sr就是找红线段,也就是红色的那一个
int query;cin>>query;
int sl=SL(0,tmp.size()-1,query),sr=SR(0,tmp.size()-1,query);
if(tmp[sl]!=query) cout<<"-1 -1"<<endl;
else cout<<sl<<" "<<sr<<endl;
}
return 0;
}
1.1.跳石头 - 蓝桥云课 (lanqiao.cn)枚举的距离
#include <bits/stdc++.h>
using namespace std;
int len,n,m;
const int N=50010;
int store[N];
bool check(int d)
{
int num=0;//记录搬走的石头的数量
int pos=0;//当前有几块石头
for(int i=1;i<=n;i++)
{
if(store[i]-pos<d) num++;//移除的就会增多
else pos=store[i];//以这一块石头当作基准供下一轮使用
}
if(num<=m) return true;
else return false;
}
int main()
{
cin>>len>>n>>m;
for(int i=1;i<=n;i++) cin>>store[i];
int l=0,r=len;
while(l<r)
{
int mid=(l+r+1)>>1;
if(check(mid)) l=mid;
else r=mid-1;
}
cout<<l<<endl;
return 0;
}
2.1.分巧克力 - 蓝桥云课 (lanqiao.cn)枚举的分完后的边长
3.1.扫地机器人 - 蓝桥云课 (lanqiao.cn)
#include<bits/stdc++.h>
using namespace std;
const int N=100050;
int robot[N];
int n,k;
bool check(int x)
{
int s=0;//这里是指当前扫到的地理位置
for(int i=1;i<=k;i++)
{
if(robot[i]-x<=s)
{
if(robot[i]<=s)//s已经大于robot[i]了,robot[i]只用扫右边的
s=robot[i]+x-1;
else s+=x;
}
else//只扫左边不可行>s了
{
return false;
}
}
if(s>=n) return true;
else return false;
}
int main()
{
cin>>n>>k;
for(int i=1;i<=k;i++)
{
cin>>robot[i];
}
sort(robot+1,robot+k+1);
int l=0,r=n;
while(l<r)
{
int mid=l+r>>1;
if(check(mid)) r=mid;
else l=mid+1;
}
cout<<(r-1)*2<<endl;
return 0;
}
浮点数二分
1.790. 数的三次方根 - AcWing题库
#include <iostream>
#include<cstdio>
using namespace std;
int main()
{
double n;cin>>n;
double l=-10000,r=10000;
while(r-l>1e-8)
{
double mid=(l + r) / 2;
if(mid*mid*mid>=n) r=mid;
else l=mid;
}
printf("%lf\n", l);
return 0;
}
2.M次方数M次方根 - 蓝桥云课 (lanqiao.cn)
#include<bits/stdc++.h>
using namespace std;
double n,m;
double l,r;
double eps=1e-8;
bool pd(int a,int b)
{
double c=1;
while(b--)//比如b=3 a*a*a
{
c=c*a;
}
if(c>=n) return 1;
else return 0;
}
int main()
{
cin>>n>>m;
l=0,r=n;
while(abs(l-r)>eps)
{
double mid=(l+r)/2;
if(pd(mid,m)) r=mid;
else l=mid;
}
printf("%.7f",r);
return 0;
}
#include<bits/stdc++.h>
using namespace std;
double n;
double l,r,mid;
double eps=1e-8;
bool pd(double a,double b)
{
double c=1;
while(b--)//比如b=3 a*a*a
{
c=c*a;
}
if(c>=n) return 1;
else return 0;
}
int main()
{
int m;
cin>>n>>m;
l=0,r=n;
while(abs(l-r)>eps)
{
mid=(l+r)/2;
if(pd(mid,m)) r=mid;
else l=mid;
}
printf("%.7f",r);
return 0;
}
十,贪心
1.常见贪心问题
1.区间调度问题
2.区间覆盖问题
3.最优装载问题
4.多机调度问题
5.结构体排序代码
2.1.翻硬币 - 蓝桥云课 (lanqiao.cn)
#include <bits/stdc++.h>
using namespace std;
string aim;
string ori;
int ans;
void switch_1(int a)
{
if(ori[a]=='*') ori[a]='o';
else ori[a]='*';
}
void switch_2(int a)
{
ans++;
switch_1(a);
switch_1(a+1);
}
int main()
{
cin>>ori;cin>>aim;
int n=ori.size();
for(int i=0;i<n;i++)
{
if(ori[i]!=aim[i]) switch_2(i);
else continue;
}
cout<<ans<<endl;;
return 0;
}
3.1.快乐司机 - 蓝桥云课 (lanqiao.cn)
#include <bits/stdc++.h>
using namespace std;
double ans=0;
struct goods{
double weight;
double value;
goods(int w,int v)
{
weight=w;
value=v;
}
};
bool myguize(const goods &g1,const goods &g2)
{
return (g1.value/g1.weight)>(g2.value/g2.weight);
}
vector<goods> yunshu;
int main()
{
int n,hezai;cin>>n>>hezai;
for(int i=1;i<=n;i++)
{
int a,b;cin>>a>>b;
yunshu.push_back(goods(a,b));
}
sort(yunshu.begin(),yunshu.end(),myguize);
vector<goods> a=yunshu;
for(int i=0;i<n;i++)
{
if(a[i].weight<hezai)
{
hezai-=a[i].weight;
ans+=a[i].value;
}
else if(a[i].weight>=hezai)
{
ans+=hezai*(a[i].value/a[i].weight);
hezai=0;break;
}
}
printf("%.1lf",ans);
return 0;
}
4.1.防御力 - 蓝桥云课 (lanqiao.cn)//思路不会纯抄代码
#include <bits/stdc++.h>
using namespace std;
struct mydata{
int id;
int weight;
}a[2000040],b[200040];
bool cmpa(mydata x,mydata y)//对于a来说的排序
{
//先按增加量排序:从小到大
if(x.weight!=y.weight) return x.weight<y.weight;
//再按字典序排序
else return x.id<y.id;
}
bool cmpb(mydata x,mydata y)//对于b来说的排序
{
if(x.weight!=y.weight) return x.weight>y.weight;
else return x.id<y.id;
}
int main()
{
int n1,n2;cin>>n1>>n2;
for(int i=1;i<=n1;i++) cin>>a[i].weight,a[i].id=i;
for(int i=1;i<=n2;i++) cin>>b[i].weight,b[i].id=i;
sort(a+1,a+n1+1,cmpa);
sort(b+1,b+n2+1,cmpb);
string s1;cin>>s1;
int idx=1,idy=1;
for(int i=0;i<(int)s1.size();i++)
{
if(s1[i]=='1') cout<<"B"<<b[idy++].id<<endl;
else cout<<"A"<<a[idx++].id<<endl;
}
cout<<"E"<<endl;
return 0;
}
5.1.答疑 - 蓝桥云课 (lanqiao.cn)//答案思路较为详细
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e3+20;
struct node{
ll s,a,e;
bool operator <(const node &x) const
{
return (s+a+e)<(x.s+x.a+x.e);
}
};
vector<struct node> aa;
int main()
{
int n;cin>>n;
for(int i=0;i<n;i++)
{
ll s,a,e;
cin>>s>>a>>e;
aa.push_back(node{s,a,e});
}
sort(aa.begin(),aa.end());
ll ans=0;
for(int i=0;i<n;i++)
{
ll s=aa[i].s,a=aa[i].a,e=aa[i].e;
ans+=(n-i)*(s+a)+(n-i-1)*e;
}
cout<<ans;
return 0;
}
6.找零问题 - 蓝桥云课 (lanqiao.cn)
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;cin>>n;
int a1=n/100;
n=n%100;
int a2=n/50;
n=n%50;
int a3=n/20;
n=n%20;
int a4=n/5;
n=n%5;
int a5=n/1;
n=n%1;
cout<<"100:"<<a1<<endl;
cout<<"50:"<<a2<<endl;
cout<<"20:"<<a3<<endl;
cout<<"5:"<<a4<<endl;
cout<<"1:"<<a5<<endl;
return 0;
}
7.小B的宿舍 - 蓝桥云课 (lanqiao.cn)
#include <cstdio>
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
int main()
{
int move[200];
//搬运次数
int N;
int T;
cin>>T;
while(T--)
{
//每次搬运的起点和终点
int from, to;
int maxAns=0;
scanf("%d", &N);
memset(move, 0, sizeof(move));
for(int i = 0; i < N; i++)
{
scanf("%d%d", &from, &to);
//将房间号映射为走廊号
from = (from - 1)/2;
to = (to - 1)/2;
//确保from<to,C++使用:swap(from, to)
if(from > to)
{
swap(from,to)
}
//统计占用走廊情况,并统计最大值
for(int j = from; j <= to; j++)
{
move[j]++;
maxAns=max(maxAns,move[j]);//找重叠的
}
}
cout<<maxAns*10<<endl;
}
}
十一,动态规划
1.0跳跃 - 蓝桥云课 (lanqiao.cn)
#include <bits/stdc++.h>
using namespace std;
int n,m,sum=-0x3f3f3f3f;
const int N=105;
int nextt[9][2]={{0,1},{0,2},{0,3},{1,0},{1,1},{1,2},{2,0},{2,1},{3,0}};
int mapp[N][N];
void dfs(int x,int y,int value)
{
value+=mapp[x][y];
if(x==n&&y==m)
{
sum=max(sum,value);
return;
}
for(int i=0;i<9;i++)
{
int tx=x+nextt[i][0];
int ty=y+nextt[i][1];
if(tx<=n && ty <=m)
dfs(tx,ty,value);
}
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>mapp[i][j];
dfs(1,1,0);
cout<<sum;
return 0;
}
value[n+5][m+5]
dp(x,y)
{
if(x==n&&y==m)
return value[n][m]
if(越界)
return 负无穷
value[x][y]=value[x][y]+max(dp(x+1,y)......,dp(2,1))
return dp(x,y)
}
2.2409. 游戏中的学问 - AcWing题库
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
LL DP[3100][3100],mod;
int n,k;
int main()
{
cin>>n>>k>>mod;
DP[3][1]=2;
for(int i=4;i<=n;i++)
{
for(int j=1;3*j<=i&&j<=k;j++)
{
DP[i][j]=DP[i-1][j]*(i-1)%mod;
DP[i][j]=(DP[i][j]+DP[i-3][j-1]*(i-1)*(i-2))%mod;
}
}
cout<<DP[n][k];
return 0;
}
十二,图论
弗洛伊德算法1.蓝桥公园 - 蓝桥云课 (lanqiao.cn)
#include <bits/stdc++.h>
using namespace std;
int n,m,q;
const long long INF=0x7f7f7f7f7f7f7f7fLL;
const int N=405;
long long dp[N][N];
void floyd()
{
for(int k=1;k<=n;k++)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]);
}
}
}
}
int main()
{
cin>>n>>m>>q;
memset(dp,0x3f,sizeof(dp));
for(int i=1;i<=n;i++)
{
int u,v;long long w;cin>>u>>v>>w;
dp[u][v]=dp[v][u]=min(dp[u][v],w);//当发生重变的时候,取最小的
}
floyd();
while(q--)
{
int s,t;
cin>>s>>t;
if(dp[s][t]==INF) cout<<"-1"<<endl;
else if(s==t) cout<<"0"<<endl;
else cout<<dp[s][t]<<endl;
}
return 0;
}
代码#include <bits/stdc++.h>
using namespace std;
int n,m,q;
const long long INF=0x3f3f3f3f3f3f3f3fLL;
const int N=405;
long long dp[N][N];
void floyd()
{
for (int k = 1; k <= n; k++)
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j]);
}
int main()
{
cin>>n>>m>>q;
memset(dp,0x3f,sizeof(dp));
for(int i=1;i<=n;i++)
{
int u,v;long long w;cin>>u>>v>>w;
dp[u][v]=dp[v][u]=min(dp[u][v],w);//当发生重变的时候,取最小的
}
floyd();
while(q--)
{
int s,t;
cin>>s>>t;
if(dp[s][t]==INF) cout<<"-1"<<endl;
else if(s==t) cout<<"0"<<endl;
else cout<<dp[s][t]<<endl;
}
return 0;
}
十三,数论
模运算:1.刷题统计 - 蓝桥云课 (lanqiao.cn)
#include <iostream>
using namespace std;
typedef long long ll;
int main()
{
ll a,b,n;cin>>a>>b>>n;
ll week=5*a+2*b;
ll days=(n/week)*7;
n%=week;
if(n<=a*5) days+=n/a+(n%a?1:0);
else{
n-=a*5;days+=5;
days+=n/b+(n%b?1:0);
}
cout<<days<<endl;
return 0;
}
#include <iostream>
using namespace std;
typedef long long ll;
//原理
//b^p mod k =(b mod k)^p mod k;
ll fastpow(ll b,ll n,ll k)
{
ll ans=1;
b = b % k;
while(n)
{
if(n&1) ans=(ans*b)%k;//ans=(ans*b)
b= (b * b) %k;//a= (a * a)
n=n>>1;
}
return ans;
}
//解释
//例如pow(a,11) 1011
//1011 ans=b; b=b^2;
//101 ans=b^3 b=b^4;
//10 b=b^8;
//1 ans=b^11;
int main()
{
ll b,n,k;cin>>b>>n>>k;
cout<<fastpow(b,n,k)<<endl;
return 0;
}
最大公约数和最小公倍数
#include<bits/stdc++.h>
using namespace std;
int gcd(int a, int b)
{
return b? gcd(b, a%b):a;
}
int lcm(int a,int b)
{
return a/gcd(a,b)*b;
}
#include<bits/stdc++.h>
using namespace std;
//c++有默认的__gcd()函数
int lcm(int a, int b){ return a / gcd(a, b) * b;}
int main(){
int a,b,c; cin>>a>>b>>c;
int k = lcm(a,b);
cout<<lcm(k,c)<<endl;
return 0;
}
素数实现
#include <iostream>
#include <cmath>
bool is_prime(long long n){
if(n <= 1)
return false; // 1不是素数
for(long long i = 2; i <= sqrt(n); i++)
if(n % i == 0)
return false; // 能整除,不是素数
return true; // 全不能整除,是素数
}
int main() {
long long number = 29; // 例子:要检查是否为素数的数值
if (is_prime(number))
std::cout << number << " 是素数。" << std::endl;
else
std::cout << number << " 不是素数。" << std::endl;
return 0;
}
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include<cstdio>
using namespace std;
const int N = 2 ^ 20 + 10;
int primes[N], cnt;//pri[i]表示存放的质数,cnt记录质数个数,全局变量默认是0
bool st[N];//记录是不是合数,全局变量默认false
void get_primes(int n)
{
for (int i = 2; i <= n; i++)从 2 开始筛
{
if (!st[i])//如果没有被划掉(表示不是合数)就说明当前i是质数
{
primes[cnt++] = i;//从primes[0]开始存放
}
for (int j = 0; primes[j] * i <= n; j++)//开始枚举已记录的质数,利用这些质数划掉合数
{
//for循环里面,i * primes[j] <= n,首先要保证划掉的合数不能大于n,不然没意义
st[primes[j] * i] = true;//划掉合数
if (i % primes[j] == 0) break;
//如果i是质数,则最多枚举到自身中断
//如果i是合数,则最多枚举到自身的最小质数中断
}
}
}
int main()
{
get_primes(12);
for (int i = 0; i < cnt; i++)
{
cout << primes[i] << " ";
}
cout << endl;
return 0;
}