我的ACM代码库

本文汇总了ACM竞赛中常见的算法和数据结构,包括博弈论问题、头文件声明、数据类型范围优化、快速幂、树状数组、矩阵快速幂、SPFA、迪杰斯特拉算法、二分图匹配、线段树和RMQ等。同时,还探讨了直线与线段相交、马拉车算法、带权并查集等几何与图论问题,适合ACM选手复习和提升。
摘要由CSDN通过智能技术生成

常用易忘

ACM常见博弈论


头文件声明

#include <iostream> 
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <iomanip>
#include <algorithm>
#include <climits>
#include <cstring>
#include <string>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <vector>
#include <list>
#define rep(i,m,n) for(int i=m;i<=n;i++)
#define rsp(it,s) for(set<int>::iterator it=s.begin();it!=s.end();it++)
const int inf_int = 2e9;
const long long inf_ll = 2e18;
#define inf_add 0x3f3f3f3f
#define MOD 1000000007
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define pi acos(-1.0)
#define pii pair<int,int>
#define Lson L, mid, rt<<1
#define Rson mid+1, R, rt<<1|1
const int maxn=5e2+10;
using namespace std;
typedef  vector<int> vi;
typedef  long long ll;
typedef  unsigned long long  ull; 
inline int read(){
   int ra,fh;char rx;rx=getchar(),ra=0,fh=1;
while((rx<'0'||rx>'9')&&rx!='-')rx=getchar();if(rx=='-')
fh=-1,rx=getchar();while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,
rx=getchar();return ra*fh;}
//#pragma comment(linker, "/STACK:102400000,102400000")
ll gcd(ll p,ll q){
   return q==0?p:gcd(q,p%q);}
ll qpow(ll p,ll q){
   ll f=1;while(q){
   if(q&1)f=f*p;p=p*p;q>>=1;}return f;}
int dir[4][2]={
   {
   -1,0},{
   1,0},{
   0,-1},{
   0,1}};
const int N = 1e7+5;

int main()
{
   
    return 0;   
} 

数据类型范围



unsigned   int   04294967295   
int   21474836482147483647 
unsigned long 04294967295
long   21474836482147483647
long long的最大值:9223372036854775807
long long的最小值:-9223372036854775808
unsigned long long的最大值:18446744073709551615

__int64的最大值:9223372036854775807
__int64的最小值:-9223372036854775808
unsigned __int64的最大值:18446744073709551615

cin cout 速度慢问题

	ios::sync_with_stdio(false);"\n"不用endl

欧拉筛法

for(int i = 2;i < 50005;i++){
   
 		if(a[i]) b[ci++] = i;
 		for(int j = 0;j < ci&&b[j]*i<50005;j++){
   
 			a[b[j]*i] = 0;
 			if(i%b[j] == 0) break;
 		}
 	}//欧拉筛法,不要太大,大于sqrt(x)后面的就没意义了,反而会是这道题超时

快速幂

LL quick_pow(LL a,LL b)
{
   
    LL res = 1;
    while(b)
    {
   
        if(b%2 != 0) res *= a;
        a *= a;
        b /= 2;
    }
    return res;
}

辗转相除法gcd和lcm

 int gcd(int a,int b){
   
     if(a%b == 0) return b;
     else return gcd(b,a%b);
 }

int gcd(int a,int b)///最大公因数,测试数据1e8,没有C++自带的__gcd(,)函数快
{
   
    return (a%b==0)?b:gcd(b,a%b);
}
int lcm(int a,int b)///最小公倍数
{
   
    return (a*b/gcd(a,b));
}
int main()
{
   
    int a,b;
    cin>>a>>b;
    cout<<gcd(a,b)<<endl<<lcm(a,b)<<endl;
}

二进制枚举


#include <bits/stdc++.h>
using namespace std;
int main()
{
   
    int n;
    cin >> n;
    for(int i = 0; i < (1<<n); i++) //从0~2^n-1个状态
    {
   
        for(int j = 0; j < n; j++) //遍历二进制的每一位
        {
   
            if(i & (1 << j))//判断二进制第j位是否存在
            {
   
                printf("%d ",j);//如果存在输出第j个元素
            }
        }
        printf("\n");
    }
    return 0;
}

二分

    int search(int array[], int n, int v)
    {
   
    int left, right, middle;
    left = 0, right = n - 1;  
    while (left <= right)
    {
   
        middle = (left + right) >>1;
        if (array[middle] > v)
        {
   
        
            right = middle - 1;
        }
        else if (array[middle] < v)
        {
   
            left = middle + 1;
        }
        else
        {
   
            return middle;
        }
    }
    return -1;
    }

kmp多串匹配模板

#include <bits/stdc++.h>
using namespace std;
char w[10000+10],t[1000000+10];
int next1[10000+10],ans;
void getnext(){
   
 int wlen = strlen(w);

 int j = 0,k = -1;
 next1[0] = -1;
 
 while(j < wlen){
   
     if(k == -1 || w[k] == w[j]){
   
         ++k;
         ++j;
         next1[j] = k;
     }
     else{
   
         k = next1[k];
     }
 }

 /* for(int i = 0;i <= wlen;i++){ */
 /*     printf("%d ",next1[i]); */
 /* } */
}

void kmp(){
   
 int wlen = strlen(w);
 int tlen = strlen(t);
 getnext();

 int i = 0,j = 0;
 while(j < tlen){
   
     if(i == -1 || w[i] == t[j]){
   
         i++;
         j++;

         if(i == wlen){
   
             ans++;
             i = next1[i];
         }
     }
     else{
   
         i = next1[i];
     }
 }
}
int main(){
   
 
 int xx;
 scanf("%d\n",&xx);
 while(xx--){
   
     memset(w,0,sizeof(w));
     memset(t,0,sizeof(t));
     scanf("%s",w);
     scanf("%s",t);
     
     ans = 0;
     kmp();
     printf("%d\n",ans);
     
 }
 return 0;
}

KMP最小循环节、循环周期:
https://blog.csdn.net/hao_zong_yin/article/details/77455285
定理:假设S的长度为len,则S存在最小循环节,循环节的长度L为len-next[len],子串为S[0…len-next[len]-1]。

(1)如果len可以被len - next[len]整除,则表明字符串S可以完全由循环节循环组成,循环周期T=len/L。

(2)如果不能,说明还需要再添加几个字母才能补全。需要补的个数是循环个数L-len%L=L-(len-L)%L=L-next[len]%L,L=len-next[len]

字符串哈希

p1220
#include<iostream>
#include<cstring>
using namespace std;
const int MaxNum = 20000000;
char ch[MaxNum];
bool lage[MaxNum];                                //用于标记是否为相同的子串
int hashArray[256];                                //存储n个字母转换成整数之后再转换成nc进制的数

int main() {
   
 int n, nc;
 while (cin >> n >> nc >> ch) {
   
     int k = 0;
     int len = strlen(ch);                    //注意此处
     for (int i = 0; i < len; i++) {
   
         if (hashArray[ch[i]] == 0) {
   
             hashArray[ch[i]] = k++;            //给nc个字母编号,如hashArray['a']=1
         }
     }
     int ans = 0;                            //记录不同子串的种数
     for (int i = 0; i <= len - n; i++) {
   
         int sum = 0;
         for (int j = i; j < i + n; j++) {
   
             sum = sum * nc + hashArray[ch[j]];//将hashArray[]的nc进制数转换成一个十进制的整数sum
         }
         if (!lage[sum]) {
                       //未出现过为false
             ans++;
             lage[sum] = true;                //出现过的为true
         }
     }
     cout << ans << endl;
 }
 return 0;
}

树状数组

int lowbit(int x){
   
 return x&(-x);
}

int update(int p,int x){
       
 while(p <= 100010){
   //数字n
     bit[p] = bit[p] + x;
     p = p + lowbit(p);
 }
}

int query(int p){
   
 int ans = 0;
 while(0 < p){
   
     ans = ans + bit[p];
     p = p - lowbit(p);
 }
 return ans;
}

矩阵快速幂hdu1005 & LightOJ - 1070

hud1005
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
struct node{
   
 ull x[2][2];
};
const int mod = 7;
node mux(node a,node b){
   
 
 node t;
 memset(t.x,0,sizeof(t.x));
 for(int i = 0;i < 2;i++)
     for(int j = 0;j < 2;j++)
         for(int k = 0;k < 2;k++){
   
             t.x[i][j] = (t.x[i][j]%mod + (a.x[i][k]*b.x[k][j])%mod)%mod;
         }

 return t;

}

node quick(ull n,node a){
   

 node t;
 memset(t.x,0,sizeof(t));

 t.x[0][0] = t.x[1][1] = 1;
 t.x[0][1] = t.x[1][0] = 0;
 while(n){
   
     if(n&1)
         t = mux(t,a);
     a = mux(a,a);
     n=n>>1;
 }
 return t;
}


int main(){
   

 ull a,b,n;
 while(cin>>a>>b>>n){
   
     if(a == 0 && b == 0 && n == 0){
   
         exit(0);
     }

     if(n == 1 || n == 2){
   
         cout<<1<<"\n";
         continue;
     }
     
     node a1;
     a1.x[0][0] = a;
     a1.x[0][1] = 1;
     a1.x[1][0] = b;
     a1.x[1][1] = 0;
     node ans = quick(n-2,a1);

     cout<<(ans.x[0][0] + ans.x[1][0])%mod<<"\n";

 }

 return 0;
}

LightOJ - 1070 
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long llu;
typedef unsigned int uint;

struct node{
   
 llu s[2][2]; 
};

node mut(node a,node b){
   

 node c;
 memset(c.s,0,sizeof(c.s));
 for(int i = 0;i < 2;i++)
     for(int j = 0;j < 2;j++)
         for(int k = 0;k < 2;k++)
             c.s[i][j] = c.s[i][j]+ b.s[k][j]*a.s[i][k];
 return c;
             
}

node quick(llu n,node p){
   

 node q;
 memset(q.s,0,sizeof(q.s));
 
 q.s[0][1] = q.s[1][0] = 0;
 q.s[1][1] = q.s[0][0] = 1;

 while(n){
   
     if(n&1)
         q = mut(p,q);
     p = mut(p,p);
     n = n/2;
 }

 return q;
}
int main(){
   
 
 llu t,cnt = 1;
 llu x,y,z;
 cin>>t;
 while(t--){
   
     cin>>x>>y>>z;
     

     if(z == 1){
   
         cout<<"Case "<<cnt++<<": "<<x<<"\n";
         continue;    
     }
     else if(z == 2){
   
         cout<<"Case "<<cnt++<<": "<<x*x-2*y<<"\n";
         continue;    
         
     }
     else if(z == 0){
   
         cout<<"Case "<<cnt++<<": "<<2<<"\n";
         continue;    
     }
     else{
   
         node a1,b1;
         a1.s[0][0] = x;
         a1.s[1][0] = x*x-2*y;
         a1.s[1][1] = 0;
         a1.s[0][1] = 0;

         b1.s[0][0] = x;
         b1.s[1][0] = -1*y;
         b1.s[0][1] = 1;
         b1.s[1][1] = 0;

         node ans = quick(z-2,b1);

         cout<<"Case "<<cnt++<<": "<<a1.s[1][0]*ans.s[0][0] + a1.s[0][0]*ans.s[1][0]<<"\n";
     }
 }
 return 0;
}

spfa hdu1874

#include <bits/stdc++.h>
using namespace std;
int dist[210],vis[210],cnt[210];//vis在对列的标志 cnt每个点的如队列次数
const int inf = 0x3f3f3f3f;
struct edge{
   
 int v;
 int cost;
 edge(int _v = 0,int _cost=0):v(_v),cost(_cost){
   };
};

vector<edge>e[210];

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

bool spfa(int start,int n)
{
   
 memset(vis,0,sizeof(vis));
 for(int i = 0;i < n;i++)
     dist[i] = inf;
 vis[start] = 1;
 dist[start] = 0;
 queue<int>que;

 while(!que.empty()) que.pop();
 que.push(start);

 memset(cnt,0,sizeof(cnt));
 cnt[start] = 1;
 while(!que.empty())
 {
   
     int u = que.front();
     que.pop();

     vis[u] = 0;

     for(int i = 0; i < e[u].size();i++ )
     {
   
         int v = e[u][i].v;
         if(dist[v] > dist[u] + e[u][i].cost){
   
             dist[v] = dist[u] + e[u][i].cost;
             if(!vis[v]){
   
                 vis[v] = 1;
                 que.push(v);
                 if(++cnt[v] > n)
                     return false;
                 //cnt[i]为入队列次数,用来判定是否存在负环回路
             }
         }
     }
 }
 return true;
}
int main(){
   

 int n,m;
 while(~scanf("%d%d",&n,&m))
 {
   
     for(int i = 0;i < n;i++)
         e[i].clear();
     int a,b,x;
     for(int i = 0;i < m;i++){
   
         scanf("%d%d%d",&a,&b,&x);
         addedge(a,b,x);
         addedge(b,a,x);
     }

     int start,end;
     scanf("%d%d",&start,&end);
     spfa(start,n);
     if(dist[end] == inf)
         printf("-1\n");
     else
         printf("%d\n",dist[end]);
 }
 return 0;
}

地杰斯特拉 p3371

#include <bits/stdc++.h>
using namespace std;
const int inf = 2147483647;
const int maxn = 100010;
struct qnode
{
   
 int v,c;
 qnode(int _v = 0,int _c = 0):v(_v),c(_c){
   }
 bool operator < (const qnode& a) const
 {
   
     return c > a.c;
 }
};

struct edge{
   
 int v,cost;
 edge(int _v = 0,int _cost = 0):v(_v),cost(_cost){
   }
};

vector <edge> e[maxn];
bool vis[maxn];
int dist[maxn];
//点的编号从1开始
//

void disa(int n,int start)
{
   
 memset(vis,0,sizeof(vis));
 for(int i = 1;i <= n;i++)
     dist[i] = inf;
 priority_queue<qnode>que;
 while(!que.empty())
     que.pop();
 dist[start] = 0;
 que.push(qnode(start,0));
 
 qnode tmp;

 while(!que.empty())
 {
   
     tmp = que.top();
     que.pop();
     int u = tmp.v;
     if(vis[u])
         continue;
     vis[u] = 1;

     for(int i = 0;i < e[u].size();i++)
     {
   
         int v = e[tmp.v][i].v;
         int cost = e[u][i].cost;
         if(!vis[v]&&dist[v] > dist[u]+cost)
         {
   
             dist[v] = dist[u] + cost;
             que.push(qnode(v,dist[v]));
         }
     }
 }
}
void addedge(int u,int v,int w)
{
   
 e[u].push_back(edge(v,w));
}

int main(){
   
 int n,m,s,v1,v2,w;
 scanf("%d%d%d",&n,&m,&s);
 for(int i = 0;i < m;i++)
 {
   
     scanf("%d%d%d",&v1,&v2,&w);
     addedge(v1,v2,w);
     /* addedge(v2,v1,w); */
 }
 disa(n,s);
 for(int i = 1;i <= n;i++)
     printf("%d ",dist[i]);
 putchar('\n');
 return 0;
}

二分图匹配hdu2063

#include <bits/stdc++.h>
using namespace std;
const int maxn = 510;
typedef long long ll;
vector<int>q[maxn];
int match[maxn],book[maxn];
int dfs(int u)
{
   
    for(size_t i = 0;i < q[u].size();i++)
    {
   
        int t = q[u][i];
        if(book[t] == 0)
        {
   
            book[t] = 1;
            if(match[t] == 0 || dfs(match[t]))
            {
   
                match[t] = u;
                return 1;
            }
        }
    }
    return 0;
}
int main(){
   

    int k,n,m,a,b,sum = 0;
    while(scanf("%d",&k)&&k){
   
        for(int i = 0;i < maxn;i++)
            q[i].clear();
        memset(book,0,sizeof(book));
        memset(match,0,sizeof(match));

        scanf("%d%d",&n,&m);
        for(int i = 0;i < k;i++)
        {
   
            scanf("%d%d",&a,&b);
            q[a].push_back(b);
        }
        
        for(int i = 0;i <= n;i++)
            match[i] = 0;

        for(int i = 1;i <= n;i++)
        {
   
            memset(book,0,sizeof(book));
            if(dfs(i))
                sum++;
        }
        printf("%d\n",sum);
    }
    return 0;
}

P1435 lcs滚动数组优化

#include<bits/stdc++.h>
using namespace std;
int dp[2][5001];
char str1[5001],str2[5001];
int main()
{
   
    int n;
    scanf("%s",str1+1);
    n = strlen(str1+1);
    for(int i = 1; i <= n; i++)
        str2[i] = str1[n-i+1];       
    for(int i = 1; i<=n; i++)
        for(int j = 1; j <= n; j++)
            if(str1[i]
  • 9
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Randy__Lambert

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值