STL 

STL有很多東西,忘了怎麼辦??

STL有很多東西,忘了怎麼辦??

忘了就查,查幾次就會記得了 !!

cppreference

container

Vector

功能比較多

可以自動改大小的陣列

 

front()

back()

第一個元素

最後一個元素

begin()     第一個元素的指標

end()     結束的指標(最後一個元素的下一個位置)

rbegin()     最後一個元素的指標

rend()     開始的指標-1(第一個元素的上一個位置)

clear()

insert()     一般不會用(很慢)

push_back()

pop_back()

resize()     (長度,數值)

empty()

size()

vector會什麼可以一直push_back()

但不用預先訂長度

試試模板

請寫一個程式,可以有幾種輸入

1: push X  推入 X

2 : pop 移除最後一個元素

3 : clear 清除vector

4 : size 印出目前長度

 

每次操作後印出整個陣列

Stack

First in Last out

推疊

推疊

能從頂端拿東西 / 放東西

名稱 功能 時間
empty() 回傳是否為空 O(1)
size() 大小 O(1)
push()
推入一元素 O(1)
pop() 刪除一元素(頂端) O(1)
swap() 交換兩stack O(1)
top() 回傳頂端元素 O(1)

#include<bits/stdc++.h>
using namespace std;

main(){
    stack<int> st;
    st.push(3);
    st.push(4)
    st.push(6);
    cout<<st.top()<<endl;
    st.pop();
    cout<<st.top()<<endl;
    st.pop();
    if(st.empty()) cout<<"empty!!"<<endl;
    else cout<<"not empty!!"<<endl;
}

AC code

#include<bits/stdc++.h>
using namespace std;
#define maxn 100005
stack<int> A,st;
int n,T,q[maxn],inst[maxn];
bool flag;
int main(){
    cin>>T;
    while(T--){
        flag = true;
        while(!A.empty()) A.pop();
        while(!st.empty()) st.pop();
        cin>>n;
        for(int i=1;i<=n;++i) inst[i]=0;
        for(int i=n;i>=1;--i) A.push(i);
        for(int i=0;i<n;++i) cin>>q[i];
        for(int i=0;i<n;++i){
            if(!inst[q[i]]){
                while(A.top()!=q[i]){
                    st.push(A.top());
                    inst[A.top()]=1;
                    A.pop();
                }
                A.pop();
            }else if(st.empty()||st.top() != q[i]){
                flag = false;
                break;
            }
            else {
                inst[st.top()] = 0;
                st.pop();
            }
        }

            if(flag) cout<<"Yes"<<endl;
            else cout<<"No"<<endl;

    }
    return 0;
}

Queue

First in First out

像是一條隊伍,前面的人可以出去,人可以從後面進入隊伍

名稱 功能 時間
empty() 回傳是否為空 O(1)
size() 大小 O(1)
push() 推入一元素 O(1)
pop() 刪除一元素(頂端) O(1)
front() 回傳開始端的元素 O(1)
back() 回傳尾端元素 O(1)

#include<bits/stdc++.h>
using namespace std;

main(){
    queue<int> Q;
    Q.push(34);
    Q.push(3);
    Q.push(65);
    Q.push(8);
    cout<<Q.front()<<endl;
    cout<<Q.back()<<endl;
    Q.pop();
    cout<<Q.front()<<endl;
    cout<<Q.back()<<endl;
    if(Q.empty()) cout<<"empty!!"<<endl;
    else cout<<"not empty!!"<<endl;
    cout<<Q.size()<<endl;
}

經常用於之後會教的BFS、單調隊列

Deque

stack + queue

頭尾都可以拿取元素或推入元素

名稱 功能 時間
empty() 回傳是否為空 O(1)
size() 大小 O(1)
front() 回傳開始端的元素 O(1)
back() 回傳尾端元素 O(1)
push_back() 從後端推入元素 O(1)
push_front() 從前端推入元素 O(1)
pop_back() 從後端刪除元素 O(1)
pop_front() 從前端刪除元素 O(1)

#include<bits/stdc++.h>
using namespace std;

main(){
    deque<int> dq;
    dq.push_front(4);
    dq.push_front(4325);
    dq.push_back(32);
    dq.push_front(1);
    dq.push_back(4);
    dq.push_back(56);
    dq.push_front(6);
    cout<<dq.front()<<endl;
    cout<<dq.back()<<endl;
    dq.pop_back();
    dq.pop_front();
    dq.pop_back();
    cout<<dq.size()<<endl;
    cout<<dq.front()<<endl;
    cout<<dq.back()<<endl;
}

Set & Multiset

set  -> 集合

想像一個黑盒子,可以有種操作

1:放入一個東西

2:拿出一個東西

3:詢問一個東西是否在裡面

BUT!!

同一個東西只能放一個

BUT!!

同一個東西只能放一個

Multiset想放幾個就放幾個

名稱 功能 時間
empty() 回傳是否為空 O(1)
size() 大小 O(1)
insert() 插入元素 O(logn)
erase() 刪除元素 O(logn)
find() 是否找到元素 O(logn)
count() 是否找到元素 O(logn)
lower_bound() 第一個大於等於 O(logn)
upper_bound() 第一個大於 O(logn)

依序給你n個數字,請你把重複的數字刪除,

並按照原本的順序印出

 

依序給你n個數字,請你把重複的數字刪除,

並按照原本的順序印出

 

ex

1 3 5 3 3 2 5   ->    1 3 2

 

順序跑過,對於每個數字,如果之前出現過,他就不能印出,否則印出

順序跑過,對於每個數字,如果之前出現過,他就不能印出,否則印出

SET  !!!

Map

類似Python中的Dictionary

一個鍵(key)映射到一個值(value)

一個鍵(key)映射到一個值(value)

ex:

營養午餐  -> ㄆㄨㄣ

牛肉麵  ->  delicious

泡麵 -> 便宜

名稱 功能 時間
empty() 回傳是否為空 O(1)
size() 大小 O(1)
[key] = val 插入元素 O(logn)
erase() 刪除元素 O(logn)
find() 是否找到元素 O(logn)
count() 是否找到元素 O(logn)
lower_bound() 第一個大於等於 O(logn)
upper_bound() 第一個大於 O(logn)
[key] 找到key對應的val O(logn)

給你n個數字,跟一個目標值k,

判斷是否存在n個數中的其中兩個和為k
若可以  -> 印出兩數字編號

否則   ->   印出   IMPOSSIBLE

n <= 200005

枚舉每兩個?

枚舉每兩個?

總共有 n^2 級別個數對 !

->  TLE 

對於每個數字,我只要往前找是否有人跟他的和是k

對於每個數字,我只要往前找是否有人跟他的和是k

並且這個元素可能會被比他後面的元素找到

對於每個數字,我只要往前找是否有人跟他的和是k

並且這個元素可能會被比他後面的元素找到

因此我可以記下某些資訊以供人來找 ??

對於每個數字,我只要往前找是否有人跟他的和是k

並且這個元素可能會被比他後面的元素找到

因此我可以記下某些資訊以供人來找 ??

MAP !

如果我的值是 a
那我要找的人就是 (k-a)

如果我的值是 a
那我要找的人就是 (k-a)

因此每次先查找前面是否有 (k-a)

有的話就印出答案

 

否則

記錄下自己的值,給後人找 !

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define maxn 200005

int n,k;
map<int,int> mp;
main(){
    cin>>n>>k;
    for(int i=1;i<=n;++i){
        int a; cin>>a;
        if(mp.count(k-a)){
            cout<<mp[k-a]<<' '<<i<<endl;
            return 0;
        }
        mp[a] = i;
    }
    cout<<"IMPOSSIBLE"<<endl;
}

AC code

Priority queue

優先的queue

優先的queue

每次拿出裡面的極值(max、min)

名稱 功能 時間
empty() 回傳是否為空 O(1)
size() 大小 O(1)
push 加入一新元素 O(logn)
pop 從後端刪除元素 O(logn)
top 回傳極值元素 O(1)

#include<bits/stdc++.h>
using namespace std;
#define int long long

main(){
    priority_queue<int> Q;
    Q.push(64);
    Q.push(2);
    Q.push(9);
    Q.push(3);
    Q.push(65);
    cout<<Q.top()<<endl;
    Q.pop();
    cout<<Q.top()<<endl;
    cout<<Q.size()<<endl;
}

有一根長度為x的棍子,我要把他切成n條棍子,

長度分別為d1、d2....dn,

每次可以把棍子切成兩半,成本為原棍子長度

ex :

長度為a的棍子切兩半cost = a

 

求最小cost

ex:

input :

8  3

2  3  3 

output:

13

8

5

3

2

3

8

5

3

2

3

正的做好像有點難,那試試反著做 !

如果從下面合併上來

如果從下面合併上來

最終切成的棍子會造成多少COST ?

8

5

3

2

3

8

5

3

2

3

8

5

3

2

3

畫出來看看每段造成的 COST

8

5

3

2

3

畫出來看看每段造成的 COST

驚人發現長度為 X 的木棍對

COST的貢獻為  X * 深度(合併次數)

驚人發現長度為 X 的木棍對

COST的貢獻為  X * 深度(合併次數)

驚人發現長度為 X 的木棍對

COST的貢獻為  X * 深度(合併次數)

因此可以直觀的想到

由於合併次數固定

驚人發現長度為 X 的木棍對

COST的貢獻為  X * 深度(合併次數)

因此可以直觀的想到

由於合併次數固定

長度長的棍子合併少次一點

短的合併多次一點

因此可以每次合併長度最短的棍子

因此可以每次合併長度最短的棍子

如何找到最短的 ?

因此可以每次合併長度最短的棍子

如何找到最短的 ?

priority_queue !!!

code

#include<bits/stdc++.h>
using namespace std;
#define int long long 
int x,n,as,a,l,r;
priority_queue<int,vector<int>,greater<int>> pq;
int main(){
    cin>>x>>n;
    for(int i=0;i<n;++i) {cin>>a; pq.push(a);}
    while(pq.size()>1){
        l = pq.top(); pq.pop();
        r = pq.top(); pq.pop();
        as += l+r;
        pq.push(l+r);
    }
    cout<<as;
 
 
    return 0;
}

bitset

bool 陣列

bool 陣列

有什麼差 ?

bool arr[size]

bitset<size>

一個bool存的資訊

卻用到與int相同的空間 !? 

一個bool存的資訊

卻用到與int相同的空間 !? 

但bitset就是確確實實節省了許多空間

一個bool存的資訊

卻用到與int相同的空間 !? 

但bitset就是確確實實節省了許多空間

因此只會用到 1/32  or  1/64 的記憶體空間

一個bool存的資訊

卻用到與int相同的空間 !? 

但bitset就是確確實實節省了許多空間

因此只會用到 1/32  or  1/64 的記憶體空間

時間複雜度可以寫成O(n/w)

w = 32 or 64

有些題目就會這樣卡掉你

名稱 功能 時間
.set(index,0or1) index項設為1 O(1)
.reset 全部設為0 O(n/w)
bitset & bitset 每項取and O(n/w)
bitset | ​bitset 每項取or O(n/w)
~bitset 每項取反 O(n/w)
<<= k 全部左移k O(1)
>>= k 全部右移k O(1)
.count 有幾個是1 O(n/w)
.any 有任何一個1 O(1)
._Find_next(index) 下一個一的位置 O(1)
._Find_first(index) 第一個1的位置 O(1)
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define maxn 200005
main(){
    bitset<20> bt;

    bt.set(10,1);
    bt[11] = 1;
    bt[12] = 1;
    bt[13] = 1;
    bt[17] = 1;

    cout<<bt<<endl;
    cout<<bt.count()<<endl;
    bt >>= 5;
    cout<<bt<<endl;

    cout<<bt._Find_first()<<endl;
    cout<<bt._Find_next(8)<<endl;

    bt.set();// 什麼都不給,全部設為1

    cout<<bt<<endl;
}

algorithm

std sort

很快的排序

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define maxn 200005

main(){
    int n,arr[maxn];
    vector<int> v;
    cin>>n;
    for(int i=0;i<n;++i){
        int a; cin>>a;
        arr[i] = a;
        v.push_back(a);
    }
    sort(arr,arr+n);
    sort(v.begin(),v.end());
    for(int i=0;i<n;++i) cout<<arr[i]<<' ';
}

如果想從大排到小 ?

如果想從大排到小 ?

greater !

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define maxn 200005

main(){
    int n,arr[maxn];
    vector<int> v;
    cin>>n;
    for(int i=0;i<n;++i){
        int a; cin>>a;
        arr[i] = a;
        v.push_back(a);
    }
    sort(arr,arr+n,greater<int>());
    sort(v.begin(),v.end(),greater<int>());
    for(int i=0;i<n;++i) cout<<arr[i]<<' ';
}

雜談&小技巧

IO優化

有些題目你再怎麼寫,就是超時,輸入量又超過1e6級別時

有些題目你再怎麼寫,就是超時,輸入量又超過1e6級別時

不妨試試io優化

有些題目你再怎麼寫,就是超時,輸入量又超過1e6級別時

不妨試試io優化

也可以當成模板打

ios::sync_with_stdio(0); 

cin.tie(0);

短短兩行就能大幅加速輸入

#include<bits/stdc++.h>
using namespace std;


main(){
    ios::sync_with_stdio(0); cin.tie(0);

}

用法就是直接打在main裡面

#include<bits/stdc++.h>
using namespace std;


main(){
    ios::sync_with_stdio(0); cin.tie(0);

}

用法就是直接打在main裡面

但要注意如果用了此優化,就不能混用cin、scanf

如何優化的??

如何優化的??

sync_with_stdio(0);

 

關閉 cin、cout、scanf、print的同步,

減少性能的損失

 

如何優化的??

sync_with_stdio(0);

 

關閉 cin、cout、scanf、print的同步,

減少性能的損失

 

也因此不能混用 cin、cout、scanf、print

如何優化的??

cin.tie(0);

 

當電腦執行cin時,會刷新輸出緩衝區,

確保了輸出在輸入之前完成,但耗費許多時間

 

 

 

如何優化的??

cin.tie(0);

 

當電腦執行cin時,會刷新輸出緩衝區,

確保了輸出在輸入之前完成,但耗費許多時間

 

 

 

因此cin.tie(0);

關閉了此動作,從而達到加速的效果

考一考大家

cpp有兩種換行方式:

endl

'\n'

哪一種比較快 ?

考一考大家

cpp有兩種換行方式:

endl

'\n'

哪一種比較快 ?

endl !

比較看看有什麼不同 !

 

#include<bits/stdc++.h>
using namespace std;
main(){
    int n; cin>>n;
    while(n--){
        int a; cin>>a;
        cout<<a<<'\n';
    }
}
#include<bits/stdc++.h>
using namespace std;
main(){
    ios::sync_with_stdio(0); cin.tie(0);
    int n; cin>>n;
    while(n--){
        int a; cin>>a;
        cout<<a<<'\n';
    }
}

struct

假如我今天要記錄一個人的資訊

我可能要記 :

假如我今天要記錄一個人的資訊

我可能要記 :

性別

身高

體重

興趣

專長

............

假如我今天要記錄一個人的資訊

我可能要記 :

名字

性別

身高

體重

興趣

專長

............

一個變數存不下ㄚㄚㄚㄚㄚㄚ

這時,你就可以使用struct,想塞什麼就塞什麼

假設我要記錄一個人..

#include<bits/stdc++.h>
using namespace std;

struct person{
    int hight,weight;
    bool gender;
    string interest,expertise,name;
};

main(){
    person a;
    a.name = "蔡孟平";
    a.hight = 200;
    a.weight = 100;
    a.gender = 1;
    a.interest = "sleep";
    a.expertise = "燒機";

    cout<<a.name<<endl;
    cout<<a.expertise<<endl;
}
struct person{
    int hight,weight;
    bool gender;
    string interest,expertise,name;
};
struct person{
    int hight,weight;
    bool gender;
    string interest,expertise,name;
};

建立完struct後

直接把他當新的型別用

struct person{
    int hight,weight;
    bool gender;
    string interest,expertise,name;
};

建立完struct後

直接把他當新的型別用

main(){
    person a;
    a.name = "蔡孟平";
    a.hight = 200;
    a.weight = 100;
    a.gender = 1;
    a.interest = "sleep";
    a.expertise = "燒機";

    cout<<a.name<<endl;
    cout<<a.expertise<<endl;
}
struct person{
    int hight,weight;
    bool gender;
    string interest,expertise,name;
};

建立完struct後

直接把他當新的型別用

main(){
    person a;
    a.name = "蔡孟平";
    a.hight = 200;
    a.weight = 100;
    a.gender = 1;
    a.interest = "sleep";
    a.expertise = "燒機";

    cout<<a.name<<endl;
    cout<<a.expertise<<endl;
}

就像是piar有first、second

甚至可以...

struct person{
    int hight,weight;
    bool gender;
    string interest,expertise,name;
};
struct area{
    string name;
    int v,population;
    vector<person> people;
};
struct nation{
    vector<area> con;
    string name;
};

如何初始化?

為什麼要初始化 ?

#include<bits/stdc++.h>
using namespace std;

struct person{
    int hight,weight;
    bool gender;
    string interest,expertise,name;
};
main(){
    person A;
    cout<<A.hight<<endl;
    cout<<A.weight<<endl;
}

方法一

#include<bits/stdc++.h>
using namespace std;

struct person{
    int hight = 0,weight = 0;
    bool gender = 0;
    string interest,expertise,name;
};
main(){
    person A;
    cout<<A.hight<<endl;
    cout<<A.weight<<endl;
}

方法二(比較常用)

#include<bits/stdc++.h>
using namespace std;

struct person{
    int hight,weight;
    bool gender;
    string interest,expertise,name;
    person(int h,int w,bool g){
        hight = h;
        weight = w;
        gender = g;
    }
};
main(){
    person A(100,100,1);
    cout<<A.hight<<endl;
    cout<<A.weight<<endl;
}

方法二(比較常用)

還可以

#include<bits/stdc++.h>
using namespace std;

struct person{
    int hight,weight;
    bool gender;
    string interest,expertise,name;
    person(int h,int w,bool g){
        hight = h;
        weight = w;
        gender = g;
    }
    person(){
        hight = 1000000;
        weight = 1000000;
        gender = 1000000;
    }
};
main(){
    person A(100,100,1);
    cout<<A.hight<<endl;
    cout<<A.weight<<endl;

    person B;
    cout<<B.hight<<endl;
    cout<<B.weight<<endl;
}

指標

指標就是

一個變數,但他存的東西是一個16進位數字的記憶體位置

#include<bits/stdc++.h>
using namespace std;

int main(){
    int a[10] = {2,4,3,5,12,5,23,6,3,6};
    cout<<a<<endl;
}

跑跑看

如何得到這個指標

所指到的,真正的值呢

如何得到這個指標

所指到的,真正的值呢

*

#include<bits/stdc++.h>
using namespace std;

int main(){
    int a[10] = {2,4,3,5,12,5,23,6,3,6};
    cout<<*a<<endl;
}

如何得到這個變數的記憶體位置呢

&

#include<bits/stdc++.h>
using namespace std;

int main(){
    int a = 5;
    int *ptr = &a;
    cout<<ptr<<endl;
}

因為指標是那個變數在記憶體中的位置

因此可以..

#include<bits/stdc++.h>
using namespace std;

int main(){
    int a = 5;
    int *ptr = &a;
    cout<<a<<endl;
    *ptr = 10;
    cout<<a<<endl;
}

直接殺到他家改

因為陣列的記憶體是連續的

所以...

#include<bits/stdc++.h>
using namespace std;

int main(){
    int a[10] = {23,4,3,5,12,5,23,6,3,6};
    cout<<*(a+4)<<endl;
    cout<<*(a+7)<<endl;

}

诶,是不是跟[ ]的功能很像 ?

int main(){
    int a[10] = {23,4,3,5,12,5,23,6,3,6};
    cout<<*(a+4)<<endl;
    cout<<*(a+7)<<endl;

    cout<<a[4]<<endl;
    cout<<a[7]<<endl;
}

其實是一模一樣的東西

有什麼用 ?

reference

如果要寫一個含式,他的功能要能更改變數的值

你可能會 ...

#include<bits/stdc++.h>
using namespace std;

void oper(int tar,int val){
    tar = val;
}
int main(){
    int a = 99;
    oper(a,5);
    cout<<a<<endl;
}

為什麼沒有改到 ?!?!

你可能會 ...

#include<bits/stdc++.h>
using namespace std;

void oper(int tar,int val){
    tar = val;
}
int main(){
    int a = 99;
    oper(a,5);
    cout<<a<<endl;
}

為什麼沒有改到 ?!?!

你改的是副本 !!!

因此要傳變數本人進去 !!

#include<bits/stdc++.h>
using namespace std;

void oper(int &tar,int val){
    tar = val;
}
int main(){
    int a = 99;
    oper(a,5);
    cout<<a<<endl;
}

小技巧

如果我想要指定輸出小數點後幾位怎麼辦?

如果我想要指定輸出小數點後幾位怎麼辦?

如果我想要指定輸出小數點後幾位怎麼辦?

cout<<fixed<<setprecision(位數);

int main(){
    double a = 1243.4251;
    cout<<a<<endl;
    cout<<fixed<<setprecision(10);
    cout<<a<<endl;
}

我好懶,不想自己寫型別

我好懶,不想自己寫型別

沒關係 ! 可以用auto,丟給編譯器弄  

#include<bits/stdc++.h>
using namespace std;

int main(){
    auto a = 938479832.23498273;
    auto b = 8493794;
    auto c = 8493547324235432944;
    cout<<typeid(a).name()<<endl;
    cout<<typeid(b).name()<<endl;
    cout<<typeid(c).name()<<endl;
}

Bento

By maxbrucelen