一:vector
vector很快,只是会占用很多内存
void solve(){
vector<int> es;
int n;
cin>>n;
rep(i,1,n){
int x;
cin>>x;
es.pb(x);
}
sort(es.begin(),es.end());
for(auto e:es) cout<<e<<' ';
puts("");
reverse(es.begin(),es.end());
for(auto e:es) cout<<e<<' ';
return 0;
}
input
4
0 7 2 1
output
0 1 2 7
7 2 1 0
vector与结构体
一维数组
void solve() {//邻接表
const int N = 5;
vector<int> h[N]; // 一个包含 N 个 vector<int> 的数组
// 添加有向边
h[0].push_back(1);
h[0].push_back(2);
h[1].push_back(2);
h[1].push_back(3);
h[2].push_back(3);
h[3].push_back(4);
// 遍历每个节点的邻接列表
for (int u = 0; u < N; u++) {
cout << "节点 " << u << " 的邻点: ";
// for(auto x : h[u]) cout<<x<<' ';
for (int i = 0; i < h[u].size(); i++) {
cout << h[u][i] << " ";
}
cout << endl;
}
}
输出
节点 0 的邻点: 1 2
节点 1 的邻点: 2 3
节点 2 的邻点: 3
节点 3 的邻点: 4
节点 4 的邻点:
h[u] 是一个 vector 对象,而 vector 支持通过下标访问其元素。通过 h[u][i] 可以访问节点 u 的第 i 个邻接节点。
区分:vector e(N)
初始化方式:
vector<int> e[N]
不会初始化其中的vector元素。(栈)–邻接表vector<int> e(N)
创建一个具有N个元素的vector,每个元素初始化为0
(默认值)。(堆)–动态数组
区分:vector path(N,N);
二维向量
vector<vector<int>> g(3,vector<int>(n+1));
vector<string> T(M, string(N, '*'));
等价于:char ans[i][j];(i:第i个字符串,j:字符串的长度)
M个字符串,每个字符串长度为N,初始化为*
二:stack
int main(){
stack<int> s;
int n;
cin>>n;
rep(i,1,n){
int x;
cin>>x;
s.push(x);//注意不是pb
}
while(s.size()){
cout<<s.top()<<'\n';
s.pop();
}
return 0;
}
input
4
2 5 6 7
output
7
6
5
2
手写栈
三:queue
注意不是 p b \color{RED}{注意不是pb} 注意不是pb
int n,m,a,b;
vector<int> e[N];
queue<int> q;
int vis[N];
void bfs(){
vis[1]=1;
q.push(1);
while(q.size()){
int x=q.front();
q.pop();
cout<<x<<'\n';
for(auto y:e[x]){
//去重
if(vis[y]) continue;
vis[y]=1;
q.push(y);
}
}
}
int main(){
cin>>n>>m;
rep(i,1,m){
cin>>a>>b;
//构造a与b的无向边
e[a].pb(b);
e[b].pb(a);
}
bfs();
return 0;
}
input
5 4
1 2
1 3
2 4
2 5
output
1
2
3
4
5
四:unordered_set
int n,c,x;
unordered_set<int> s;
int main(){
cin>>n;
while(n--){
cin>>c>>x;
if(c==1) s.insert(x);
else s.count(x)?puts("Y"):puts("N");
}
return 0;
}
input
5
1 6
1 2
1 7
2 6
2 5
output
Y
N
五:unordered_map
基于hash,只有映射关系
与map
相比,没有去重、排序
一旦访问过就会生成key
,使用erase()
清除键
int n,c;
string str;
unordered_map<string ,int> h;
int main(){
cin>>n;
while(n--){
cin>>c>>str;
if(c==1) h[str]++;
else{
if(h.count(str)) cout<<h[str]<<'\n';
else puts("N");
}
}
return 0;
}
input
6
1 dx
1 abc
1 dx
1 aaa
2 dx
2 ab
output
2
N
六:IOS
注意: \color{RED}{注意:} 注意:
- 要是用到了 scanf,printf,puts,gets 这些就关掉
IOS
- getline也可以不用关
IOS
,因为getline也用cin
iota函数+vector
头文件
#include<numeric>
用于填充[first,last)中元素的值,起始值为value
int main(){
int n,l,r;
cin>>n>>l>>r;
l--;
vector<int>a(n);
iota(a.begin(),a.end(),1);
reverse(a.begin()+l,a.begin()+r);
rep(i,0,n-1)
cout<<a[i]<<" \n"[i==n-1];
return 0;
}
input
5 2 4
output
1 4 3 2 5
__builtin_popcount(x)
返回x二进制中1的 个数
bitset
bitset相当于一个bool数组,但是优点是两个bitset之间可以进行按位运算。
bitset<10>a//初始值全是0
/*
string s="1010101";
bitset<10> a1(s);
cout<<a1<<endl;//0001010101 前面补0,且编号从9逐次递减
*/
bitset<4> foo (string("1001"));
bitset<4> bar (string("0011"));
foo^=bar; //1010(foo对bar按位异或后赋值给foo)
foo&=bar; //0010(按位与后赋值给foo)
foo|=bar; //0011(按位或后赋值给foo)
foo<<=2; //1100(左移2位,低位补0,有自身赋值)
foo>>=1; //0110(右移1位,高位补0,有自身赋值)
a.set() //将所有位变成1
a.set(k) //将第k位变成1,超限会报错
a.set(k,1);
a.set(k,0);
a.reset() //清空bitset
a.reset(k) //把第k位变成0
a.flip() //将所有位按位取反
a.flip(k) //将第k位按位取反
a.count() //返回bitset中1的个数
a.all() //若bitset内全是1返回1,否则返回0
atcoder 358_c
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin>>n>>m;
//char s[n][n]
vector<string> s(n);
rep(i,0,n-1) cin>>s[i];
//bool b[n][10]
vector<bitset<10>> b(n);
rep(i,0,n-1)
rep(j,0,m-1)
if(s[i][j]=='o')
b[i][j]=1;
int ans=n;//!!!
for(int x=0;x<(1<<n);x++){
bitset<10> bx(x);
bitset<10> sum;
rep(i,0,n-1)
if(bx[i])
sum |= b[i];
if(sum.count()==m) ans=min(ans,(int)bx.count());
}
cout<<ans;
return 0;
}
string
int main(){
string s[5]={"mon","tues","wed","thur","fri"};
rep(i,0,4){
cout<<s[i]<<" \n"[i==4];
}
/*
mon tues wed thur fri
[回车]
*/
return 0;
}
字词修正
s[i]=(s[i]-'a'+n)%26+'a';
转char数组
printf("%s", s); // 编译错误
printf("%s", s.data()); // 编译通过,但是是 undefined behavior
printf("%s", s.c_str()); // 一定能够正确输出
find()功能
统计单词数(
1308
)
\color{blue}{统计单词数(1308)}
统计单词数(1308)
string a,s;
int main(){
cin>>a;
getchar();//!!!
getline(cin,s);
// rep(i,0,SZ(s)-1){
// if(s[i]>='A' && s[i]<='Z') s[i]+=32;
// }
transform(a.begin(),a.end(),a.begin(),::tolower);//使a小写化
// rep(i,0,SZ(a)-1){
// if(a[i]>='A' && a[i]<='Z') a[i]+=32;
// }
transform(s.begin(),s.end(),s.begin(),::tolower);//小写化
s.insert(0," ");//让b前面加个空格 之后用find不怕查不到第一个
a=a+' ';
a.insert(a.begin(),' ');
//查找的话以首尾加空格,否则可能查找到其他单词里的字符相同但不是个单独的单词
//ec:cat != catter
if(s.find(a)==-1){
cout<<"-1";
}else{
int n=0,sum=0;
while(s.find(a,n) != -1){
sum++;
n=s.find(a,n)+1;
}
cout<<sum<<' '<<s.find(a);
}
return 0;
}
字符串反转
sscanf & sprintf
1.sscanf:从字符串中解析出整数
2.sprintf:将多个整数和运算符的格式化为字符串
只能与 c h a r [ ] 兼容,无法与 s t r i n g 兼容 \color{red}{只能与char[ ]兼容,无法与string兼容} 只能与char[]兼容,无法与string兼容
int T,c,d;
char a;
char s[N],b[N];
int main(){
cin>>T;
while(T--){
cin>>b;
if(b[0]>='a' && b[0]<='z'){
a=b[0];//如果是运算符就存入a,然后输入数字
cin>>c>>d;
}else{
//如果是数字就转换b为int存储到第一个数字
sscanf(b,"%d",&c);//不要漏了&(b->c)
cin>>d;
}
memset(s,0,sizeof s);
if(a=='a') sprintf(s,"%d+%d=%d",c,d,c+d);
else if(a=='b') sprintf(s,"%d-%d=%d",c,d,c-d);
else if(a=='c') sprintf(s,"%d*%d=%d",c,d,c*d);
cout<<s<<endl<<strlen(s)<<endl;//输出字符串和字符串长度
}
return 0;
}
next_permutation
next_permutation只能获得下一个排列,如果要获得全排列,那么就需要先对数组进行
sort
排序对于排列的个数,如果出现相同的元素(9496),则使用捆绑法 A 2 2 ⋅ A 3 3 A^{2}_{2}\cdot A^{3}_{3} A22⋅A33,否则(1234),则 A 4 4 A^{4}_{4} A44
int main(){
string s;
cin>>s;//输入9496
sort(all(s));
// cout<<s<<endl;
int i=1;
do{
cout<<i<<' '<<s<<endl;
i++;
}while(next_permutation(all(s)));//获取下一个排列
/*
1 4699
2 4969
3 4996
4 6499
5 6949
6 6994
7 9469
8 9496
9 9649
10 9694
11 9946
12 9964
*/
return 0;
}
结构体排序
#include<iostream>
#include<algorithm>//使用 next_permutation()和sort()需要导入的头文件
using namespace std;
struct test{//结构体test
int val;
};
bool cmp(test t1,test t2){//自定义的排列
return t1.val<t2.val;
}
int main(){
test t[4];//结构体数组
t[0].val=1;
t[1].val=2;
t[2].val=3;
t[3].val=4;
do{
for(int i=0;i<4;i++){//打印排列
cout<<t[i].val<<' ';
}
cout<<endl;
}while(next_permutation(t,t+4,cmp));//获取下一个排列
}
Avoid K Palindrome 2 AtCoder - abc363_c
int n,k;
string s;
int main(){
cin>>n>>k>>s;
sort(s.begin(),s.end());
int ans=0;
do{
bool ok=true;
rep(i,0,n-k){
bool pal=true;
// rep(j,1,k-1-j) 错误
for(int j=0;j<k-1-j;j++)
if(s[i+j]!=s[i+k-1-j]){
pal=false;
break;
}
if(pal){
ok=false;
break;
}
}
if(ok) ans++;
}while(next_permutation(s.begin(),s.end()));
cout<<ans;
return 0;
}
双指针
判断回文串
void solve(){
int n;
cin>>n;
while(n--){
string s;
cin >> s;
bool ans=1;
int i=0,j=s.size()-1;
while(i<j){
if(s[i]!=s[j]){
ans=0;
break;
}
i++,j--;
}
if(ans) cout << "yes" << endl;
else cout << "no" << endl;
}
}
朴素写法
bool check(string s){
rep(i,1,SZ(s)/2)
if(s[i]!=s[SZ(s)-i-1]) return false;
return true;
}
void solve(){
int n;
string s;
cin >> n;
while(n--){
cin >> s;
if(check(s)) cout<<"yes"<<endl;
else cout<<"no"<<endl;
}
}
调整回文串
将 s[i] 和 s[j] 变成相同字符所需的最小操作次数
注意:
m
i
n
对比两个个以上要用花括号
\color{RED}{注意:min对比两个个以上要用花括号}
注意:min对比两个个以上要用花括号
int a=5,b=9,c=6,d=0;
cout<<min({a,b,c,d});
core code
int res;
string s;
int main(){
cin>>s;
for(int i=0,j=SZ(s)-1;i<j;i++,j--)
res += min({abs(s[i] - s[j]), abs(s[i] - 26 - s[j]), abs(s[i] + 26 - s[j])});
cout<<res;
return 0;
}
朴素写法
void solve()
{
string s;
cin >> s;
int ans = 0;
for(int i = 0;i < s.size()/2;++i)
{
ans += min(abs(s[i] - s[s.size() - 1 - i]),26 -abs(s[i] - s[s.size() - 1 - i]) );
}
cout << ans << "\n";
}
杂题
矩阵快速打印
- 输入图
//数组名是首元素的地址
//二维数组名又是一维数组的地址(行地址)
char g[N][N];//只能为char,且输入一定没空格
for(int i=0;i<n;i++) cin>>g[i];
- 打印
int main(){
a[0]=1;
rep(i,1,6) a[i]=a[i-1]*3;//3的幂次
cin>>n;
int m=a[n];
rep(i,0,m-1)
rep(j,0,m-1)
g[i][j]='#';
dfs(n,0,0);//print .
rep(i,0,m-1) puts(g[i]);//quick print
return 0;
}