BUAA_C++算法板子积累_动态规划、图算法、计算几何、FFT

Hello

#include <iostream>
#include <cstdio>
#include <cctype>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <algorithm>
#include <queue>
#include <stack>

using namespace std;
typedef long long ll;

int main() {
    cout << "Hello world!" << endl;
    return 0;
}

标准库

<algorithm>

__gcd(a, b)				// 求两个数的最大公因数
__builtin_popcount(a)			// 求 int 的二进制里多少个 1

is_sorted(a, a + n)			// 是否升序
is_sorted_until(a, a + n)		// 到哪里是升序
sort(a, a + n)				// 不稳定排序(默认升序)
sort(a, a + n, greater<int>())	        // 降序排序
stable_sort(a, a + n)			// 稳定排序
nth_element(a, a + k, a + n)	        // 将第 k 大元素放到 a[k]
unique(begin, end)			// 对有序数组去重,返回末尾地址

max(a, b)				// 返回较大值
min(a, b)				// 返回较小值
max_element(a, a + n)			// 返回最大值位置
min_element(a, a + n)			// 返回最小值位置

lower_bound(a, a + n, key)		// 返回第一个不小于 key 的元素的位置
upper_bound(a, a + n, key)		// 返回第一个大于 key 的元素的位置
binary_search(a, a + n, key)	        // 二分查找是否存在

is_heap(a, a + n)			// 判断是否为大顶堆
is_heap_until(a, a + n)			// 到哪里是大顶堆
make_heap(a, a + n)			// 区间建堆
push_heap(a, a + n)			// 末尾元素入堆并调整,与 push_back() 配合
pop_heap(a, a + n)			// 堆顶移到末尾并调整,与 pop_back() 配合
sort_heap(a, a + n)			// 升序堆排序

is_permutation()			// 两个序列是否互为另一个的排序
next_permutation()			// 下一个排序
prev_permutation()			// 上一个排序

fill(a, a + n, val)			// 批量赋值
reverse(a, a + n)			// 数组翻转

<vector>

v.at(k)					// 访问 v[k]
v.front()				// 首元素
v.back()				// 末元素
v.begin()				// 首地址(迭代器)
v.end()					// 末地址(迭代器)
v.empty()				// 是否空
v.size()				// 大小
v.max_size()				// 最大空间
v.clear()				// 清除
v.insert(pos, item)			// 在 pos(迭代器) 位置插入 item
v.eraze(pos)				// 擦除 pos(迭代器) 位置的元素
v.push_back(item)			// 末尾插入
v.pop_back()				// 末尾删除

<queue>

/*----- queue -----*/
q.front()				// 访问队头
q.back()				// 访问队尾
q.empty()				// 是否空
q.size()				// 大小
q.push(item)				// item 入队
q.emplace(item)				// item 替换队尾
q.pop()					// 出队
/*----- priority_queue -----*/
priority_queue<int, vector<int>, greater<int>> pq
pq.top()				// 访问队首
pq.empty()				// 优先队列是否空
pq.size()				// 大小
pq.push(item)				// 插入 item
pq.pop()				// 出队

<stack>

s.top()					// 访问栈顶
s.empty()				// 栈是否空
s.size()				// 大小
s.push(item)				// item 入栈
s.emplace(item)				// item 替换栈顶
s.pop()					// 出栈

<set>

/*----- set -----*/
s.size()				// 大小
s.empty()				// 是否空
s.clear()				// 清除
s.insert(key)				// 插入
s.erase(pos/key)			// 删除
s.count(key)				// 是否存在
s.find(key)				// 查找,成功返回位置,失败返回 s.end()
/*----- multiset -----*/
ms.size()				// 大小
ms.empty()				// 是否空
ms.clear()				// 清除
ms.insert(key)				// 插入
ms.erase(pos/key)			// 删除
ms.count(key)				// 计数
ms.find(key)				// 查找,成功返回位置,失败返回 s.end()

<map>

/*----- map -----*/
/*----- mulmap -----*/

<unordered_set>

/*----- unordered_set -----*/
/*----- unordered_multiset -----*/

<unordered_map>

/*----- unordered_map -----*/
/*----- unordered_multimap -----*/

分治

逆序对计数

#include <iostream>

using namespace std;
typedef long long ll;

int temp[200005];

ll solve(int a[], int left, int right);

int main() {
    int n;
    int a[200005] = {};
    cin >> n;
    for (int i = 0; i < n; i++)
        cin >> a[i];
    cout << solve(a, 0, n - 1);
    return 0;
}
ll solve(int a[], int left, int right) {
    if (left == right)
        return 0;
    else {
        int mid = (right - left) / 2 + left;
        ll s1 = solve(a, left, mid);
        ll s2 = solve(a, mid + 1, right);
        ll s3 = 0;
        int i = left, j = mid + 1, k = 0;
        while (i <= mid && j <= right) {
            if (a[i] <= a[j]) {
                temp[left + k] = a[i];
                k++;
                i++;
            } else {
                temp[left + k] = a[j];
                s3 += (mid - i + 1);
                k++;
                j++;
            }
        }
        if (i <= mid)
            while (i <= mid) {
                temp[k + left] = a[i];
                k++;
                i++;
            }
        else
            while (j <= right) {
                temp[k + left] = a[j];
                k++;
                j++;
            }
        for (int l = left; l <= right; l++)
            a[l] = temp[l];
        return s1 + s2 + s3;
    }
}

动态规划

01 背包

#include <iostream>
#include <algorithm>

#define ll long long
#define MAX_NUM 1005   //物品数量
#define MAX_CAP 100005 //最大容量
using namespace std;

ll dp[MAX_CAP];
int v[MAX_NUM];
int w[MAX_NUM];

ll backBag(ll Bag[], int *value, int *weight, int num, int cap) {
    // dp数组,价值,重量,容量
    for(int i = 0; i <= cap; i++)
        Bag[i] = 0;
    for (int i = 1; i <= num; i++)
        for (int j = cap; j >= weight[i]; j--) //倒着dp
            Bag[j] = max(Bag[j - weight[i]] + value[i], Bag[j]);
    return Bag[cap];
}

int main() {
    int n, k;
    cin >> n >> k;
    for (int i = 1; i <= n; i++)
        cin >> v[i] >> w[i];
    cout << backBag(dp, v, w, n, k);
    return 0;
}

完全背包

#include <iostream>
#include <algorithm>

#define ll long long
#define MAX_NUM 10005    //物品数量
#define MAX_CAP 10000005 //最大容量
using namespace std;

ll dp[MAX_CAP];
int v[MAX_NUM];
int w[MAX_NUM];

ll backBag(ll Bag[], int *value, int *weight, int num, int cap) {
    // dp数组,价值,重量,容量
    for(int i = 0; i <= cap; i++)
        Bag[i] = 0;
    for (int i = 1; i <= num; i++)
        for (int j = weight[i]; j <= cap; j++) //正着dp
            Bag[j] = max(Bag[j - weight[i]] + value[i], Bag[j]);
    return Bag[cap];
}

int main() {
    int n, k;
    cin >> k >> n;
    for (int i = 1; i <= n; i++)
        cin >> w[i] >> v[i];
    cout << backBag(dp, v, w, n, k);
    return 0;
}

分组背包

#include <iostream>
#include <algorithm>

typedef long long ll;

const int MAX = 1005;

struct {
    int cnt;
    ll ID[MAX];
} group[MAX];   //用一个结构体来存储每一组的物品编号

ll dp[MAX];
ll val[MAX];
ll weight[MAX];

ll group_bag(int cap, int max_group);

using namespace std;

int main() {
//    freopen("a.in", "r", stdin);
//    freopen("a.out", "w", stdout);
    int n, m;
    cin >> m >> n;
    int a, b, k, max_group = 0;
    for (int i = 1; i <= n; i++) {
        cin >> a >> b >> k;
        weight[i] = a;
        val[i] = b;
        group[k].ID[group[k].cnt++] = i;
        max_group = max(max_group, k);
    }
    cout << group_bag(m, max_group);
    return 0;
}

ll group_bag(int cap, int max_group) {
    for (int i = 0; i <= max_group; i++)            // 第一层组循环
        for (ll j = cap; j >= 0; j--)               // 第二层容量倒着循环
            for (int k = 0; k < group[i].cnt; k++)  // 第三层组内循环
                if (j >= weight[group[i].ID[k]])
                    dp[j] = max(dp[j],
                                dp[j - weight[group[i].ID[k]]] + val[group[i].ID[k]]);
    return dp[cap];
}

最大子列和

#include <iostream>
#include <algorithm>

#define MAX 1000005
#define ll long long
using namespace std;

int a[MAX];

ll maxSubArray(int *array, int n) {
    ll Max = -0x3f3f3f3f3f3f3f3f;
    ll sum = 0;
    for (int i = n - 1; i >= 0; i--) {
        if (sum <= 0)
            sum = array[i];
        else
            sum += array[i];
        Max = max(sum, Max);
    }
    return Max;
}

int main() {
    int n;
    cin >> n;
    for (int i = 0; i < n; i++)
        cin >> a[i];
    cout << maxSubArray(a, n);
    return 0;
}

LCS 最长公共子序列

#include <iostream>
#include <string>
#define MAX 1005
using namespace std;

struct Tab{
    int x, y;
} trac[MAX][MAX];

int lcs[MAX][MAX];

void print_lcs(string str, int i, int j);

int main() {
    int k;
    cin >> k;
    string sa, sb;
    cin >> sa >> sb;
    int la = (int)sa.length();
    int lb = (int)sb.length();
    for (int i = 1; i <= la; i++) {
        for (int j = 1; j <= lb; j++) {
            if (sa[i - 1] == sb[j - 1]) {
                lcs[i][j] = lcs[i - 1][j - 1] + 1;
                trac[i][j] = {i - 1, j - 1};
            } else if (lcs[i - 1][j] >= lcs[i][j - 1]) {
                lcs[i][j] = lcs[i - 1][j];
                trac[i][j] = {i - 1, j};
            } else {
                lcs[i][j] = lcs[i][j - 1];
                trac[i][j] = {i, j - 1};
            }
        }
    }
    if(k == 0)
        cout << lcs[la][lb];
    else
        print_lcs(sa, la, lb);
    return 0;
}

void print_lcs(string str, int i, int j){
    if(i == 0 || j == 0)
        return ;
    if(trac[i][j].x == i - 1 && trac[i][j].y == j - 1){
        print_lcs(str, i - 1, j - 1);
        cout << str[i - 1];
    }else if(trac[i][j].x == i - 1 && trac[i][j].y == j)
        print_lcs(str, i - 1, j);
    else
        print_lcs(str, i, j - 1);
}

最小编辑距离

#include <iostream>
#include <string>
#define MAX 2005
using namespace std;

int min3(int a, int b, int c) {
    int m = a;
    if (b < m)
        m = b;
    if (c < m)
        return c;
    return m;
}
int minDistance(string word1, string word2) {
    int dp[2][MAX] = {};
    int l1 = word1.length();
    int l2 = word2.length();
    for (int j = 0; j <= l2; j++)
        dp[0][j] = j;
    for (int i = 1; i <= l1; i++) {
        dp[1][0] = i;
        for (int j = 1; j <= l2; j++)
            if (word1[i - 1] == word2[j - 1])
                dp[1][j] = dp[0][j - 1];
            else
                dp[1][j] = min3(dp[0][j - 1], dp[0][j], dp[1][j - 1]) + 1;
        for (int j = 0; j <= l2; j++)
            dp[0][j] = dp[1][j];
    }
    return dp[0][l2];
}
int main() {
    string a;
    string b;
    cin >> a >> b;
    cout << minDistance(a, b);
    return 0;
}

最长单调子序列

// 严格单调递增子列的长度
int lsrsa(const vector<int> &a) {
    vector<int> sa;
    for (auto x: a) {
        if (sa.empty() || x > sa.back())
            sa.push_back(x);
        else
            *lower_bound(sa.begin(), sa.end(), x) = x;
    }
    return (int) sa.size();
}
// 单调不减子列的长度
int lrsa(const vector<int> &a) {
    vector<int> sa;
    for (auto x: a) {
        if (sa.empty() || x >= sa.back())
            sa.push_back(x);
        else
            *upper_bound(sa.begin(), sa.end(), x) = x;
    }
    return (int) sa.size();
}

图算法

链式前向星

struct Edge{
    int to, w, next;			//终点,权值,前驱
} e[E_MAX];

int cnt_E = 0;
int head[V_MAX];			//需要先初始化为-1

void intList(int n){
    memset(head, -1, sizeof(head));
}

void addEdge(int x, int y, int w){
    e[cnt_E].to = y;          	        //保存终点
    e[cnt_E].next = head[x]; 	        //添加链接
    head[x] = cnt++;			//更新表头
}

Dijkstra 最短路(标准版)

#include <iostream>
#include <vector>
#include <cstring>

#define V_MAX 100005
#define INF 0x3f3f3f3f3f3f3f3f

using namespace std;
typedef long long ll;

struct Edge {
    int to;
    ll weight;
};

vector<Edge> e[V_MAX];
ll dis[V_MAX];
bool vis[V_MAX];
int n, m;

void addEdge(int u, int v, ll w);
void dijkstra(int s);

int main() {
    int s;
    cin >> n >> m >> s;
    int x, y;
    ll w;
    for (int i = 0; i < m; ++i) {
        cin >> x >> y >> w;
        addEdge(x, y, w);
    }
    dijkstra(s);
    // 最短路保存在 dis 中
    for (int i = 1; i <= n; i++) {
        if (dis[i] == INF)
            cout << -1 << " ";
        else
            cout << dis[i] << " ";
    }
    return 0;
}

void addEdge(int u, int v, ll w) {
    e[u].push_back({v, w});
}

void dijkstra(int s) {
    memset(dis, 0x3f, sizeof(dis));
    dis[s] = 0;
    for (int i = 1; i <= n; i++) {
        int u = 0;
        ll mind = INF;
        for (int j = 1; j <= n; j++)
            if (!vis[j] && dis[j] < mind) {
                u = j;
                mind = dis[j];
            }
        vis[u] = true;
        for (auto ed: e[u]) {
            int v = ed.to;
            ll w = ed.weight;
            if (dis[v] > dis[u] + w)
                dis[v] = dis[u] + w;
        }
    }
}

Dijkstra 最短路(堆优化)

#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>

#define  V_MAX 100005
#define INF 0x3f3f3f3f3f3f3f3f

using namespace std;

typedef long long ll;

struct Edge {
    int to;
    ll w;
};

struct Node {
    ll dis;
    int u;
    bool operator>(const Node &b) const {return dis > b.dis; }
};

vector<Edge> e[V_MAX];

void addEdge(int u, int v, ll w) {
    e[u].push_back({v, w});
}

vector<ll> dijkstra(int s) {
    priority_queue<Node, vector<Node>, greater<Node>> q;
    vector<ll> dis(V_MAX);
    fill(dis.begin(),  dis.end(), INF);
    vector<bool> vis(V_MAX);
    dis[s] = 0;
    q.push({0, s});
    while (!q.empty()){
        int u = q.top().u;
        q.pop();
        if(vis[u])continue;
        vis[u] = true;
        for (auto ed : e[u]){
            int v = ed.to;
            ll w = ed.w;
            if(dis[v] > dis[u] + w){
                dis[v] = dis[u] + w;
                q.push({dis[v], v});
            }
        }
    }
    return dis;
}

int main() {
    int n, m;
    int s;
    cin >> n >> m >> s;
    int x, y, w;
    for (int i = 0; i < m; i++) {
        cin >> x >> y >> w;
        addEdge(x, y, w);
    }
    vector<ll> dis = dijkstra(s);
    for (int i = 1; i <= n; i++) {
        cout << dis[i] << " ";
    }
    return 0;
}

Floyd 最短路

#include <algorithm>
#include <cstring>
#include <iostream>

#define V_MAX 510				// 结点数
#define INF 0x3f3f3f3f3f3f3f3f

using namespace std;
typedef long long ll;

ll f[V_MAX][V_MAX];				// 邻接矩阵存图

int main() {
    int n, m, p;
    ll x, y, w;
    cin >> n >> m >> p;
    for (x = 1; x <= n; x++)
        for (y = 1; y <= n; y++)
            f[x][y] = INF;
    for (int i = 1; i <= n; i++)
        f[i][i] = 0;
    
    /*-----初始化部分-----*/
    
    for (int i = 0; i < m; i++) {
        cin >> x >> y >> w;
        if (w < f[x][y])			// 考虑重边的情况
            f[x][y] = w;
    }
    
    /*-----读入-----*/
    
    for (int k = 1; k <= n; k++)
        for (x = 1; x <= n; x++)
            for (y = 1; y <= n; y++)
                f[x][y] = min(f[x][y], f[x][k] + f[k][y]);
    
    /*----- Floyd -----*/
    
    for (int i = 0; i < p; i++) {
        cin >> x >> y;
        if (f[x][y] != INF)
            cout << f[x][y] << endl;
        else
            cout << "-1" << endl;
    }
    
    /*-----输出-----*/
    return 0;
}

Kruskal 最小生成树

#include <algorithm>
#include <iostream>

#define V_MAX 300005
#define E_MAX 500005

using namespace std;
typedef long long ll;

struct Edge {
    int x, y, w;
    bool operator<(const Edge &b) const { return w < b.w; }
} e[E_MAX];

int v[V_MAX];

int Find(int x);
bool isUnion(int x, int y);
void Union(int x, int y);	//合并
void makeSet(int n);		//初始化并查集

int main() {
    int n, m;
    cin >> n >> m;
    makeSet(n);
    for (int i = 0; i < m; i++)
        cin >> e[i].x >> e[i].y >> e[i].w;
    sort(e, e + m);
    int cnt = 0;
    ll sum = 0;
    for(int i = 0; cnt < n - 1; i++){
        if(isUnion(e[i].x, e[i].y))
            continue;
        cnt++;
        sum += e[i].w;
        Union(e[i].x, e[i].y);
    }
    cout << sum;
    return 0;
}

void makeSet(int n) {
    for (int i = 1; i <= n; i++)
        v[i] = i;
}

int Find(int x) {
    if (v[x] == x)
        return x;
    return v[x] = Find(v[x]);
}

bool isUnion(int x, int y) { return Find(x) == Find(y); }
void Union(int x, int y) { v[Find(y)] = Find(x); }

Kahn 拓扑排序

#include <cstring>
#include <iostream>
#include <queue>
#include <vector>

#define E_MAX 400005
#define V_MAX 100005

using namespace std;

struct Edge {			//链式前向星,存边的起点、终点、和前驱
    int x, y, next;
} e[E_MAX];

int head[V_MAX]; 		//下标是起点的表头,存第一个边的编号,初始化为 -1
int id[V_MAX];			//每个点的入度
int cnt;			//存储的边数

void addEdge(int x, int y);
bool Kahn(int n);

int main() {
    int n, m, x, y;
    cin >> n >> m;
    
    fill(head + 1, head + 1 + n, -1);
   	
    /*----- 初始化 -----*/
    
    for (int i = 0; i < m; i++) {
        cin >> x >> y;
        addEdge(x, y);
    }
    
    /*----- 读入边 -----*/
    
    Kahn(n);
    return 0;
}
void addEdge(int x, int y) {
    e[cnt].x = x;          		//起点
    e[cnt].y = y;          		//终点
    e[cnt].next = head[x]; 		//添加
    id[y]++;
    head[x] = cnt++;			//更新表头
}
bool Kahn(int n) {
    priority_queue<int> q;		//优先队列
    for (int i = 1; i <= n; i++) {
        if (id[i] == 0)
            q.push(i);			//把入度为0的点入队
    }
    vector<int> ans;			//数组保存结果
    while (!q.empty()) {
        int x = q.top();		//出队
        q.pop();
        ans.push_back(x);
        int edge = head[x];
        while (edge != -1) {
            id[e[edge].y]--;		//删除边
            if (id[e[edge].y] == 0)
                q.push(e[edge].y);
            edge = e[edge].next;
        }
    }
    if (ans.size() == n) {
        for (int an : ans)
            cout << an << " ";
        return true;
    }
    
    /*----- 无环则输出并返回真 -----*/
    
    return false;
}

Dinic 最大流

#include <algorithm>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
typedef long long ll;
const int V_MAX = 205;
const int E_MAX = 5005;
const ll LL_INF = 0x3f3f3f3f3f3f3f3f;

ll max_stream = 0;
int cnt_E = 0;
int n, m, s, t;

struct Edge {
    int to;
    int nxt;
    ll val;
} e[E_MAX * 2];

int head[V_MAX];
int depth[V_MAX];

void addEdge(int x, int y, int w);
void read();
bool bfs();
ll Dinic();

int main() {
    ios::sync_with_stdio(false);
    cin >> n >> m >> s >> t;
    
    fill(head + 1, head + 1 + n, -1);
    
    /*----- 读入并初始化 -----*/
    
    read();
    cout << Dinic();
    return 0;
}
void addEdge(int x, int y, int w) {
    e[cnt_E].to = y;
    e[cnt_E].val = w;
    e[cnt_E].nxt = head[x];
    head[x] = cnt_E++;
}
void read() {
    int u, v, w;
    for (int i = 0; i < m; i++) {
        cin >> u >> v >> w;
        addEdge(u, v, w);
        addEdge(v, u, 0);
    }
}
bool bfs() {
    memset(depth, 0, sizeof(depth));
    depth[s] = 1;
    queue<int> q;
    q.push(s);
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        for (int i = head[u]; i > -1; i = e[i].nxt) {
            int v = e[i].to;
            if (e[i].val && !depth[v]) {
                depth[v] = depth[u] + 1;
                q.push(v);
            }
        }
    }
    if (depth[t] != 0)
        return true;
    return false;
}

ll dfs(int pos, ll in) {
    if (pos == t)
        return in;
    ll out = 0;
    for (int u = head[pos]; u > -1 && in; u = e[u].nxt) {
        int v = e[u].to;
        if (e[u].val && depth[v] == depth[pos] + 1) {
            ll res = dfs(v, min(e[u].val, in));
            e[u].val -= res;
            e[u ^ 1].val += res;
            in -= res;
            out += res;
        }
    }
    if (out == 0)
        depth[pos] = 0;
    return out;
}
ll Dinic() {
    while (bfs())
        max_stream += dfs(s, LL_INF);
    return max_stream;
}

二分图匹配

#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>

using namespace std;

struct pos {
    int x, y;
};

vector<pos> left;
vector<pos> right;

struct augment_path {
    // 结点编号从 0 开始
    vector<vector<int>> g;
    vector<int> pa;
    vector<int> pb;
    vector<int> vis;
    int n, m;
    int dfn;
    int res;

    augment_path(int _n, int _m) : n(_n), m(_m) {
        pa = vector<int>(n, -1);
        pb = vector<int>(m, -1);
        vis = vector<int>(n);
        g.resize(n);
        res = dfn = 0;
    }

    void add(int from, int to) {
        g[from].push_back(to);
    }

    bool dfs(int v) {
        vis[v] = dfn;
        for (int u: g[v])
            if (pb[u] == -1) {
                pb[u] = v;
                pa[v] = u;
                return true;
            }
        for (int u: g[v])
            if (vis[pb[u]] != dfn && dfs(pb[u])) {
                pa[v] = u;
                pb[u] = v;
                return true;
            }
        return false;
    }

    int solve() {
        while (true) {
            dfn++;
            int cnt = 0;
            for (int i = 0; i < n; i++)
                if (pa[i] == -1 && dfs(i))
                    cnt++;
            if (cnt == 0)
                break;
            res += cnt;
        }
        return res;
    }
};

int main() {
    int n, m, e;
    cin >> n >> m >> e;
    augment_path solver(n, m);
    int u, v;
    for(int i = 0; i < e; i++){
        cin >> u >> v;
        solver.add(u - 1, v - 1);
    }
    cout << solver.solve() << endl;
    return 0;
}

计算几何

线段相交计数

#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

struct Point {
    int x, y;

    Point operator+(const Point &b) const {
        return {x + b.x, y + b.y};
    }

    Point operator-(const Point &b) const {
        return {x - b.x, y - b.y};
    }

    Point operator*(const int &b) const {
        return {x * b, y * b};
    }

    int operator^(const Point &b) const {
        return x * b.y - y * b.x;
    }
};

struct Line {
    Point p;
    Point q;
};

vector<Line> lines;

bool intersect(Line l1, Line l2);

bool onSegment(Point point, Line line);

int main() {
    int n, cnt = 0;
    cin >> n;
    int x1, y1, x2, y2;
    for (int i = 0; i < n; i++) {
        cin >> x1 >> y1 >> x2 >> y2;
        lines.push_back({{x1, y1},
                         {x2, y2}});
    }
    for (int i = 0; i < n; i++)
        for (int j = 0; j < i; j++)
            if (intersect(lines[i], lines[j]))
                cnt++;
    cout << cnt;
    return 0;
}

bool intersect(Line l1, Line l2) {
    int d1 = (l1.q - l1.p) ^ (l2.p - l1.p);
    int d2 = (l1.q - l1.p) ^ (l2.q - l1.p);
    int d3 = (l2.q - l2.p) ^ (l1.p - l2.p);
    int d4 = (l2.q - l2.p) ^ (l1.q - l2.p);
    if (d1 * d2 < 0 && d3 * d4 < 0)
        return true;
    if (d1 == 0 && onSegment(l2.p, l1))
        return true;
    if (d2 == 0 && onSegment(l2.q, l1))
        return true;
    if (d3 == 0 && onSegment(l1.p, l2))
        return true;
    if (d4 == 0 && onSegment(l1.q, l2))
        return true;
    return false;
}

bool onSegment(Point point, Line line) {
    if (point.x >= min(line.p.x, line.q.x) &&
        point.x <= max(line.p.x, line.q.x) &&
        point.y >= min(line.p.y, line.q.y) &&
        point.y <= max(line.p.y, line.q.y))
        return true;
    return false;
}

Graham 凸包 + 旋转卡壳

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>

using namespace std;

const int MAX = 200005;
const double eps = 1e-7;

struct Point {
    double x, y;

    Point operator+(const Point &b) const {
        return {x + b.x, y + b.y};
    }

    Point operator-(const Point &b) const {
        return {x - b.x, y - b.y};
    }

    double operator^(const Point &b) const {
        return x * b.y - y * b.x;
    }

    bool operator<(const Point &b) const {
        if (x != b.x)
            return x < b.x;
        return y < b.y;
    }
};

Point p[MAX];
Point s[MAX];
int top;

void selMin(int n);
int cmp(Point a, Point b);
bool equal(double a, double b);
double dis(Point a, Point b);
void graham(int n);
double s_sqr(Point a, Point b, Point c);
double diameter();

int main() {
    int n;
    cin >> n;
    for (int i = 0; i < n; i++)
        cin >> p[i].x >> p[i].y;
    selMin(n);
    sort(p + 1, p + n, cmp);
    graham(n);
    printf("%.6f", sqrt(diameter())) ;
    return 0;
}

void selMin(int n) {
    Point Min = p[0];
    int IDMin = 0;
    for (int i = 0; i < n; i++)
        if (p[i] < Min) {
            Min = p[i];
            IDMin = i;
        }
    swap(p[0], p[IDMin]);
}

int cmp(Point a, Point b) {
    double x = (a - p[0]) ^ (b - p[0]);
    if (x > 0)
        return 1;
    if (equal(x, 0) && (dis(a, p[0]) < dis(b, p[0])))
        return 1;
    return 0;
}

double dis(Point a, Point b) {
    double x = a.x - b.x;
    double y = a.y - b.y;
    return x * x + y * y;
}

void graham(int n) {
    top = 1;
    s[0] = p[0];
    s[1] = p[1];
    for (int i = 2; i < n; i++) {
        while (top > 1 && ((p[i] - s[top]) ^ (s[top - 1] - s[top])) <= 0)
            top--;
        s[++top] = p[i];
    }
}

double s_sqr(Point a, Point b, Point c) {
    return fabs((a - b) ^ (c - b));
}

double diameter() {
    double diam = 0;
    int j = 2;
    s[++top] = s[0];
    if (top < 3)
        return dis(s[0], s[1]);
    for (int i = 0; i < top - 1; i++) {
        while (s_sqr(s[i], s[i + 1], s[j]) <
               s_sqr(s[i], s[i + 1], s[(j + 1) % top]))
            j = (j + 1) % top;
        diam = max(diam, max(dis(s[i], s[j]), dis(s[i + 1], s[j])));
    }
    return diam;
}
bool equal(double a, double b){
    return fabs(a - b) < eps;
}

其他算法

多项式乘法-FFT

#include <iostream>
#include <vector>
#include <cmath>

const double Pi = acos(-1);
const int MAX = 4000005;
using namespace std;
typedef long long ll;

struct Complex {
    double x, y;

    Complex operator+(const Complex &b) const {
        return {x + b.x, y + b.y};
    }

    Complex operator-(const Complex &b) const {
        return {x - b.x, y - b.y};
    }

    Complex operator*(const Complex &b) const {
        return {x * b.x - y * b.y, x * b.y + y * b.x};
    }
} f[MAX], p[MAX], sav[MAX];
void dft(Complex *f, int len);

void idft(Complex *f, int len);

int main() {
    int n, m;
    cin >> n >> m;
    for (int i = 0; i <= n; i++)
        cin >> f[i].x;
    for (int i = 0; i <= m; i++)
        cin >> p[i].x;
    for (m += n, n = 1; n <= m; n <<= 1);
    dft(f, n);
    dft(p, n);
    for (int i = 0; i < n; i++)
        f[i] = f[i] * p[i];
    idft(f, n);
    for (int i = 0; i <= m; i++)
        cout << (int) (f[i].x / n + 0.49) << " ";
    return 0;
}

void dft(Complex *f, int len) {
    if (len == 1)
        return;
    Complex *fl = f, *fr = f + len / 2;
    for (int k = 0; k < len; k++)
        sav[k] = f[k];
    for (int k = 0; k < len / 2; k++) {
        fl[k] = sav[k << 1];
        fr[k] = sav[k << 1 | 1];
    }
    dft(fl, len / 2);
    dft(fr, len / 2);
    Complex tG = {cos(2 * Pi / len), sin(2 * Pi / len)};
    Complex buf = {1, 0};
    for (int k = 0; k < len / 2; k++) {
        sav[k] = fl[k] + buf * fr[k];
        sav[k + len / 2] = fl[k] - buf * fr[k];
        buf = buf * tG;
    }
    for (int k = 0; k < len; k++)
        f[k] = sav[k];
}

void idft(Complex *f, int len) {
    if (len == 1)
        return;
    Complex *fl = f, *fr = f + len / 2;
    for (int k = 0; k < len; k++)
        sav[k] = f[k];
    for (int k = 0; k < len / 2; k++) {
        fl[k] = sav[k << 1];
        fr[k] = sav[k << 1 | 1];
    }
    idft(fl, len / 2);
    idft(fr, len / 2);
    Complex tG = {cos(2 * Pi / len), -sin(2 * Pi / len)};
    Complex buf = {1, 0};
    for (int k = 0; k < len / 2; k++) {
        sav[k] = fl[k] + buf * fr[k];
        sav[k + len / 2] = fl[k] - buf * fr[k];
        buf = buf * tG;
    }
    for (int k = 0; k < len; k++)
        f[k] = sav[k];
}

高精度乘法-FFT

#include <iostream>
#include <cmath>
#include <cstring>

const double Pi = acos(-1);
const int MAX = 4000005;
using namespace std;
typedef long long ll;

struct Complex {
    double x, y;

    Complex operator+(const Complex &b) const {
        return {x + b.x, y + b.y};
    }

    Complex operator-(const Complex &b) const {
        return {x - b.x, y - b.y};
    }

    Complex operator*(const Complex &b) const {
        return {x * b.x - y * b.y, x * b.y + y * b.x};
    }
} f[MAX], p[MAX], sav[MAX];

ll ans[MAX];
void dft(Complex *f, int len);

void idft(Complex *f, int len);

int main() {
    char a[MAX], b[MAX];
    scanf("%s%s", a, b);
    int n = strlen(a);
    int m = strlen(b);
    for(int i = 0; i < n; i++)
        f[i].x = a[n - i - 1] - '0';
    for(int i = 0; i < m; i++)
        p[i].x = b[m - i - 1] - '0';
    for (m += n, n = 1; n <= m; n <<= 1);
    dft(f, n);
    dft(p, n);
    for (int i = 0; i < n; i++)
        f[i] = f[i] * p[i];
    idft(f, n);
    for (int i = 0; i <= m; i++)
        ans[i] = (ll) (f[i].x / n + 0.49);
    for(int i = 0; i < MAX; i++){
        ans[i + 1] += (ans[i] / 10);
        ans[i] %= 10;
    }
    int t = MAX - 1;
    while (ans[t] == 0)
        t--;
    while (t >= 0)
        cout << ans[t--];
    cout << endl;
    return 0;
}

void dft(Complex *f, int len) {
    if (len == 1)
        return;
    Complex *fl = f, *fr = f + len / 2;
    for (int k = 0; k < len; k++)
        sav[k] = f[k];
    for (int k = 0; k < len / 2; k++) {
        fl[k] = sav[k << 1];
        fr[k] = sav[k << 1 | 1];
    }
    dft(fl, len / 2);
    dft(fr, len / 2);
    Complex tG = {cos(2 * Pi / len), sin(2 * Pi / len)};
    Complex buf = {1, 0};
    for (int k = 0; k < len / 2; k++) {
        sav[k] = fl[k] + buf * fr[k];
        sav[k + len / 2] = fl[k] - buf * fr[k];
        buf = buf * tG;
    }
    for (int k = 0; k < len; k++)
        f[k] = sav[k];
}

void idft(Complex *f, int len) {
    if (len == 1)
        return;
    Complex *fl = f, *fr = f + len / 2;
    for (int k = 0; k < len; k++)
        sav[k] = f[k];
    for (int k = 0; k < len / 2; k++) {
        fl[k] = sav[k << 1];
        fr[k] = sav[k << 1 | 1];
    }
    idft(fl, len / 2);
    idft(fr, len / 2);
    Complex tG = {cos(2 * Pi / len), -sin(2 * Pi / len)};
    Complex buf = {1, 0};
    for (int k = 0; k < len / 2; k++) {
        sav[k] = fl[k] + buf * fr[k];
        sav[k + len / 2] = fl[k] - buf * fr[k];
        buf = buf * tG;
    }
    for (int k = 0; k < len; k++)
        f[k] = sav[k];
}

KMP 字符串匹配

#include <iostream>
#include <vector>
#include <string>

using namespace std;

vector<int> prefix(string str);

int main(){
    string text;
    string key;
    cin >> text;
    cin >> key;
    int kl = key.length();
    vector<int> kmp = prefix(key);
    int k = 0;
    for(int i = 0; i < text.length(); i++){
        while (k && key[k] != text[i])
            k = kmp[k - 1];
        if(text[i] == key[k])
            k++;
        if(k == kl)
            cout << i - k + 2 << endl;
    }
    for(auto x: kmp)
        cout << x << " ";
    return 0;
}
vector<int> prefix(string str){
    int l = (int) str.length();
    vector<int> pre(l);
    for(int i = 1; i < l; i++){
        int j = pre[i - 1];
        while (j && str[j] != str[i])
            j = pre[j - 1];
        if(str[j] == str[i])
            j++;
        pre[i] = j;
    }
    return pre;
}

其它

快速幂取余

ll fast_pow_mod(ll a, ll b, ll m){
    a %= m;
    ll res = 1;
    while (b > 0) {
        if (b & 1) res = res * a % m;
        a = a * a % m;
        b >>= 1;
    }
    return res;
}

快速打质数表

vector<int> generate_prime_list(int n) {
    if (n <= 2)
        return vector<int>{2};
    if (n <= 3)
        return vector<int>{2, 3};
    if (n <= 5)
        return vector<int>{2, 3, 5};
    vector<int> prime_list = {2, 3, 5};
    int i = 1;
    int x;
    while (true) {
        x = 6 * i + 1;
        if (x > n)
            break;
        if (is_prime(x, prime_list))
            prime_list.push_back(x);
        x = 6 * i + 5;
        if (x > n)
            break;
        if (is_prime(x, prime_list))
            prime_list.push_back(x);
        i++;
    }
    return prime_list;
}

bool is_prime(int x, const vector<int> &prime_list) {
    for(auto u: prime_list){
        if(x % u == 0)
            return false;
        if(u * u > x)
            return true;
    }
    return false;
}

鸣谢

posted @ 2022-01-24 00:00  Only(AR)  阅读(383)  评论(0编辑  收藏  举报