四處搜刮整理模板

1.篩法

int prime[maxn];  
bool is_prime[maxn];

int sieve(int n){
    int p = 0;
    for(int i = 0; i <= n; ++i)
        is_prime[i] = true;
    is_prime[0] = is_prime[1] = false;
    for (int i = 2; i <= n; ++i){   //  注意數組大小是n
        if(is_prime[i]){
            prime[p++] = i;
            for(int j = i + i; j <= n; j += i)  //  輕剪枝,j必定是i的倍數
                is_prime[j] = false;
        }
    }
    return p;   //  返回素數個數
}
2.快速冪算法

typedef long long LL;   //  視數據大小的情況而定

LL powerMod(LL x, LL n, LL m)
{
    LL res = 1;
    while (n > 0){
        if  (n & 1) //  判斷是否爲奇數,若是則true
            res = (res * x) % m;
        x = (x * x) % m;
        n >>= 1;    //  相當於n /= 2;
    }
    return res;
}

3.大數階乘

#include <iostream>
#include <cstdio>
using namespace std;
typedef long long LL;
const int maxn = 100010;
int num[maxn], len;
/*
    在mult函數中,形參部分:len每次調用函數都會發生改變,n表示每次要乘以的數,最終返回的是結果的長度
    tip: 階乘都是先求之前的(n-1)!來求n!
    初始化Init函數很重要,不要落下
*/
void Init() {
    len = 1;
    num[0] = 1;
}
int mult(int num[], int len, int n) {
    LL tmp = 0;
    for(LL i = 0; i < len; ++i) {
         tmp = tmp + num[i] * n;    //從最低位開始,等號左邊的tmp表示當前位,右邊的tmp表示進位(之前進的位)
         num[i] = tmp % 10; //  保存在對應的數組位置,即去掉進位後的一位數
         tmp = tmp / 10;    //  取整用於再次循環,與n和下一個位置的乘積相加
    }
    while(tmp) {    //  之後的進位處理
         num[len++] = tmp % 10;
         tmp = tmp / 10;
    }
    return len;
}
int main() {
    Init();
    int n;
    n = 1977; // 求的階乘數
    for(int i = 2; i <= n; ++i) {
        len = mult(num, len, i);
    }
    for(int i = len - 1; i >= 0; --i)
        printf("%d",num[i]);    //  從最高位依次輸出,數據比較多采用printf輸出
    printf("\n");
    return 0;
}


4.大數加法

#include<stdio.h>
#include<string.h>
char s1[1001],s2[1001];
int a[1001],b[1001],c[1001];
int main()
{
    int i,k,n,m;
    scanf("%s%s",s1,s2);
        memset(c,0,sizeof(c));
        n=strlen(s1);
        m=strlen(s2);
        for(i=0; i<n; i++)
            a[i]=s1[n-i-1]-'0';
        for(i=0; i<m; i++)
            b[i]=s2[m-i-1]-'0';
        if(n>m) k=n;
        else k=m;
        for(i=0; i<=k; i++)
        {
            c[i]+=a[i]+b[i];
            if(c[i]>9)
            {
                c[i+1]++;
                c[i]%=10;
            }
        }
        i=k;
        while(c[i]==0)
            i--;
        if(i<0) printf("0");
        else
        {
            for(;i>=0;i--)
                printf("%d",c[i]);
        }
        printf("\n");
    return 0;
}

5.全排列

void Pern(int list[], int k, int n) {   //  k表示前k個數不動僅移動後面n-k位數
    if (k == n - 1) {
        for (int i = 0; i < n; i++) {
            printf("%d", list[i]);
        }
        printf("\n");
    }else {
        for (int i = k; i < n; i++) {   //  輸出的是滿足移動條件所有全排列
            swap(list[k], list[i]);
            Pern(list, k + 1, n);
            swap(list[k], list[i]);
        }
    }
}

6.二分搜索

//  left爲最開始元素, right是末尾元素的下一個數,x是要找的數
int bsearch(int *A, int left, int right, int x){
    int m;
    while (left < right){
        m = left + (right - left) / 2;
        if (A[m] >= x)  right = m;   else left = m + 1;    
        // 如果要替換爲 upper_bound, 改爲:if (A[m] <= v) x = m+1; else y = m;     
    }
    return left;
}
/*
    最後left == right  
    如果沒有找到135577找6,返回7  
    如果找有多少的x,可以用lower_bound查找一遍,upper_bound查找一遍,下標相減  
    C++自帶的lower_bound(a,a+n,x)返回數組中最後一個x的下一個數的地址 
    upper_bound(a,a+n,x)返回數組中第一個x的地址
    如果a+n內沒有找到x或x的下一個地址,返回a+n的地址  
    lower_bound(a,a+n,x)-upper_bound(a,a+n,x)返回數組中x的個數
*/

7.二分法求最長遞增子序列

#include<bits/stdc++.h>
using namespace std;
int n;
int ch[100005];
int dp[100005];
int Binary(int x,int len1)
{
    int left=1;
    int right=len1;
    while(left<=right)
    {
        int mid1=left+(right-left)/2;
        if(dp[mid1]==x)
            return mid1;
        else if(dp[mid1]<x)
        {
            left=mid1+1;
        }
        else
            right=mid1-1;
    }
    return left;
}
int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=1;i<=n;i++)
         {
             cin>>ch[i];
         }
         memset(dp,0,sizeof(dp));
         dp[1]=ch[1];
         int len1=1;
         for(int i=2;i<=n;i++)
         {
             if(ch[i]>dp[len1])
             {
                 dp[++len1]=ch[i];
             }
             else
                {
                    int t=Binary(ch[i],len1);
                    dp[t]=ch[i];
                }
         }
         cout<<len1<<endl;
    }
    return 0;
}
8,。最長公共子序列

void getnext(char str[maxn], int nextt[maxn]) {
    int j = 0, k = -1;
    nextt[0] = -1;
    while (j < m) {
        if (k == -1 || str[j] == str[k]) {
            j++;
            k++;
            nextt[j] = k;
        }
        else
            k = nextt[k];
    }
}
void kmp(int a[maxn], int b[maxn]) {    
    int nextt[maxm];    
    int i = 0, j = 0;    
    getnext(b, nextt);    
    while (i < n) {    
        if (j == -1 || a[i] == b[j]) { // 母串不動,子串移動    
            j++;    
            i++;    
        }    
        else {    
            // i不需要回溯了    
            // i = i - j + 1;    
            j = nextt[j];    
        }    
        if (j == m) {    
            printf("%d\n", i - m + 1); // 母串的位置減去子串的長度+1    
            return;    
        }    
    }    
    printf("-1\n");
}   

9.並查集

int father[maxn];   //  儲存i的father父節點  
void makeSet() {  
    for (int i = 0; i < maxn; i++)   
        father[i] = i;  
}  
int findRoot(int x) {   //  迭代找根節點
    int root = x; // 根節點  
    while (root != father[root]) { // 尋找根節點  
        root = father[root];  
    }  
    while (x != root) {  
        int tmp = father[x];  
        father[x] = root; // 根節點賦值  
        x = tmp;  
    }  
    return root;  
}  
void Union(int x, int y) {  //  將x所在的集合和y所在的集合整合起來形成一個集合。  
    int a, b;  
    a = findRoot(x);  
    b = findRoot(y);  
    father[a] = b;  // y連在x的根節點上   或father[b] = a爲x連在y的根節點上;  
}  
/*
    在findRoot(x)中:
    路徑壓縮 迭代 最優版
    關鍵在於在路徑上的每個節點都可以直接連接到根上
*/
10.克魯斯卡爾算法

/*
    第一步:點、邊、加入vector,把所有邊按從小到大排序
    第二步:並查集部分 + 下面的code
*/
void Kruskal() {    
    ans = 0;    
    for (int i = 0; i<len; i++) {    
        if (Find(edge[i].a) != Find(edge[i].b)) {    
            Union(edge[i].a, edge[i].b);    
            ans += edge[i].len;    
        }    
    }    
}  

11.普利姆算法

struct node {  
    int v, len;  
    node(int v = 0, int len = 0) :v(v), len(len) {}  
    bool operator < (const node &a)const {  // 加入隊列的元素自動按距離從小到大排序  
        return len> a.len;  
    }  
};
vector<node> G[maxn];
int vis[maxn];
int dis[maxn];
void init() {  
    for (int i = 0; i<maxn; i++) {  
        G[i].clear();  
        dis[i] = INF;  
        vis[i] = false;  
    }  
}  
int Prim(int s) {  
    priority_queue<node>Q; // 定義優先隊列  
    int ans = 0;  
    Q.push(node(s,0));  // 起點加入隊列  
    while (!Q.empty()) {   
        node now = Q.top(); Q.pop();  // 取出距離最小的點  
        int v = now.v;  
        if (vis[v]) continue;  // 同一個節點,可能會推入2次或2次以上隊列,這樣第一個被標記後,剩下的需要直接跳過。  
        vis[v] = true;  // 標記一下  
        ans += now.len;  
        for (int i = 0; i<G[v].size(); i++) {  // 開始更新  
            int v2 = G[v][i].v;  
            int len = G[v][i].len;  
            if (!vis[v2] && dis[v2] > len) {   
                dis[v2] = len;  
                Q.push(node(v2, dis[v2]));  // 更新的點加入隊列並排序  
            }  
        }  
    }  
    return ans; 
}  
12.迪傑斯特拉算法

struct node {  
    int v, len;  
    node(int v = 0, int len = 0) :v(v), len(len) {}  
    bool operator < (const node &a)const {  //  距離從小到大排序  
        return len > a.len;  
    }  
};  
vector<node>G[maxn];  
bool vis[maxn];  
int dis[maxn];
void init() {  
    for (int i = 0; i<maxn; i++) {  
        G[i].clear();  
        vis[i] = false;  
        dis[i] = INF;  
    }  
}  
int dijkstra(int s, int e) {  
    priority_queue<node>Q;  
    Q.push(node(s, 0)); //  加入隊列並排序  
    dis[s] = 0;  
    while (!Q.empty()) {  
        node now = Q.top();     //  取出當前最小的  
        Q.pop();  
        int v = now.v;  
        if (vis[v]) continue;   //  如果標記過了, 直接continue  
        vis[v] = true;  
        for (int i = 0; i<G[v].size(); i++) {   //  更新  
            int v2 = G[v][i].v;  
            int len = G[v][i].len;  
            if (!vis[v2] && dis[v2] > dis[v] + len) {  
                dis[v2] = dis[v] + len;  
                Q.push(node(v2, dis[v2]));  
            }  
        }  
    }  
    return dis[e];  
}  

13.弗洛伊德算法

for (int i = 0; i < n; i++) {   //  初始化爲0  
    for (int j = 0; j < n; j++)  
        scanf("%lf", &dis[i][j]);  
}  
for (int k = 0; k < n; k++) {  
    for (int i = 0; i < n; i++) {  
        for (int j = 0; j < n; j++) {  
            dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);  
        }  
    }
}

14.揹包

//  01揹包:  
void bag01(int cost,int weight)  {  
    for(i = v; i >= cost; --i)  
    dp[i] = max(dp[i], dp[i-cost]+weight);  
}  
//  完全揹包:  
void complete(int cost, int weight)  {  
    for(i = cost ; i <= v; ++i)  
    dp[i] = max(dp[i], dp[i - cost] + weight);  
}  
//  多重揹包:  
void multiply(int cost, int weight, int amount)  {  
    if(cost * amount >= v)  
        complete(cost, weight);  
    else{  
        k = 1;  
        while (k < amount){  
            bag01(k * cost, k * weight);  
            amount -= k;  
            k += k;  
        }  
        bag01(cost * amount, weight * amount);  
    }  
}  
15.博弈論

BASH

#define _MAX 10000
int a[_MAX];
int b[_MAX];
int bash(int N, int K)
{
    if (N % (K + 1) == 0) 
    {
        return 2;
    }
    return 1;
}
int main()
{
    int T;
    scanf("%d", &T);
    for (int i = 0; i < T; i++)
    {
        scanf("%d%d", a + i, b + i);
    }
    for (int i = 0; i < T; i++)
    {
        if (bash(a[i], b[i]) == 1)
        {
            printf("A\n");
        }
        else
        {
            printf("B\n");
        }
    }
    return 0; 
}


NIM

int main(int argc, const char * argv[])
{
    int N, stone, tag = 0;
    scanf("%d", &N);
    while (N--)
    {
        scanf("%d", &stone);
        tag ^= stone;
    }
    //tag爲0則爲後手贏,否則爲先手贏
    printf("%c\n", tag == 0 ? 'B' : 'A');
    return 0;
}

SG函數打表

const int MAX_DIG = 64;
//  SG打表
//  f[]:可以取走的石子個數
//  sg[]:0~n的SG函數值
//  hash[]:mex{}
int f[MAX_DIG];
int sg[MAX_DIG];
int hash[MAX_DIG];
void getSG(int n)
{
    memset(sg, 0, sizeof(sg));
    for (int i = 1; i <= n; i++)
    {
        memset(hash, 0, sizeof(hash));
        for (int j = 1; f[j] <= i; j++)
        {
            hash[sg[i - f[j]]] = 1;
        }
        for (int j = 0; j <= n; j++)    //  求mes{}中未出現的最小的非負整數
        {
            if (hash[j] == 0)
            {
                sg[i] = j;
                break;
            }
        }
    }
}

SG DFS

const int MAX_DIG = 64;
//  DFS
//  注意 S數組要按從小到大排序 SG函數要初始化爲-1 對於每個集合只需初始化1遍
//  n是集合s的大小 S[i]是定義的特殊取法規則的數組
int s[MAX_DIG];
int sg[MAX_DIG * 100];
int n;
int SG_dfs(int x)
{
    if (sg[x] != -1)
    {
        return sg[x];
    }
    bool vis[MAX_DIG];
    memset(vis, 0, sizeof(vis));
    for (int i = 0; i < n; i++)
    {
        if (x >= s[i])
        {
            SG_dfs(x - s[i]);
            vis[sg[x - s[i]]] = 1;
        }
    }
    int e;
    for (int i = 0; ; i++)
    {
        if (!vis[i])
        {
            e = i;
            break;
        }
    }
    return sg[x] = e;
}

Wythoff

int main()
{
    int t, a, b, m, k;
    scanf("%d", &t);
    while (t--)
    {
        scanf("%d%d", &a, &b);
        if (a > b)
        {
            a ^= b;
            b ^= a;
            a ^= b;
        }
        m = b - a;
        k = (int)(m * (1 + sqrt(5)) / 2.0);
        //m = ? * a
        //k = m / ?
        //?:黃金分割數
        //如果a == k,則爲後手贏,否則先手贏(奇異局)
        printf("%s\n", a == k ? "B" : "A");
    }
    return 0;
}





持續更新中。。。。。。

發佈了67 篇原創文章 · 獲贊 100 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章