acm比赛常用模板

乱七八糟模板

  • 头文件,宏定义,读入挂
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define ll long long
#define ull unsigned long long
#define PI acos(-1.0)
#define eps 1e-12
#define fi first
#define se second
#define MEM(a,b) memset((a),(b),sizeof(a))
#define mod(x) ((x)%MOD)
#define pii pair
#define wz cout<<"-----"<
const int INF_INT = 2147483647;
const ll INF_LL = 9223372036854775807LL;
const ull INF_ULL = 18446744073709551615Ull;
const ll P = 92540646808111039LL;

const ll maxn = 1e5 + 10, MOD = 1e9 + 7;
const int Move[4][2] = {-1,0,1,0,0,1,0,-1};
const int Move_[8][2] = {-1,-1,-1,0,-1,1,0,-1,0,1,1,-1,1,0,1,1};

inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 结构体重载运算符
//与平时cmp函数 相反
bool operator < (const node &p) const {
        return r > p.r;
    }
   
   
   
   
  • 1
  • 2
  • 3
  • 4

数据结构

  • 树状数组

/*
单点更新,区间查询,(也可区间更新加),逆序对等等
*/
int lowerbit(int x) {
    return x & -x;
}

void add(int p, int x) {
    while (p < maxn) {
        d[p] += x;
        p += lowerbit(p);
    }
}
int sum(int p) {
    int res = 0;
    while (p) {
        res += d[p];
        p -= lowerbit(p);
    }
    return res;
}

   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

数论模板

  • 快速幂
ll quick_pow(ll a,ll b) {
    ll res = 1;
    while (b) {
        if (b & 1) {
            res = a * res;
        }
        a = a * a;
        b >>= 1;
    }
    return res;
}
   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 矩阵快速幂
#include
#define ll long long
#define mod(x) ((x)%MOD)

using namespace std;

const ll MOD = 1e9 + 7;

struct mat{
    ll m[3][3];
}a,ans,unit;

void init() {
    memset(unit.m,0,sizeof(unit.m));
    memset(a.m,0,sizeof(a.m));
    unit.m[0][0] = 1;
    unit.m[1][1] = 1;
    a.m[0][0] = 3;
    a.m[0][1] = 1;
    a.m[1][0] = 1;
    a.m[1][1] = 3;
}

mat operator * (mat m1,mat m2) {
    mat t;
    ll r;
    for(int i = 0;i < 3;i++) {
        for(int j = 0;j < 3;j++) {
            r = 0;
            for(int k = 0;k < 3;k++) {
                r = mod(r*1ll + mod(mod(m1.m[i][k])*1ll*mod(m2.m[k][j])));
            }
            t.m[i][j] = r;
        }
    }
    return t;
}

mat quick_pow(ll x) {
    mat t = unit;
    while(x) {
        if(x & 1) {
            t = t*a;
        }
        a = a*a;
        x >>= 1;
    }
    return t;
}
int main(){
    init();
    ans = quick_pow(n);
}
   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 素数的两种筛法
bool isp[maxn];
int p[maxn], len;

bool isp[100];
void init() {
    int m = (int)sqrt(maxn+0.5);
    for(int i = 2;i <= m;i++) {
        if(!isp[i]) {
            for(int j = i*i;j <= maxn;j += i) {
                isp[j] = true;
            }
        }
    }
}

void init() { //推荐这个,较快
    isp[0] = isp[1] = true;
    for (int i = 2; i < maxn; i++) {
        if(!isp[i]) p[++len] = i;
        for (int j = 1; j <= len && p[j]*i < maxn; j++) {
            isp[i*p[j]] = true;
            if (i%p[j] == 0) break;
        }
    }
}
   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 欧拉函数 
    在数论,对正整数n,欧拉函数是小于n的正整数中与n互质的数的数目(φ(1)=1)。
int euler_phi(int n){ //单个值
    int m = (int)sqrt(n + 0.5);
    int ans = n;
    for (int i = 2;i <= m;i++){
        if (n%i == 0){       //如果存在素因子
            ans = ans/i*(i-1); 
            while (n%i == 0) n/=i;
        }
    }
    if(n > 1) ans = ans/n*(n-1); //考虑n本身
    return ans;
}

void phi_table(int n,int *phi){ //欧拉表
    for (int i = 1;i <= n;i++) phi[i] = i;
    for(int i = 2;i <= n;i++){
        if(phi[i] == i){   //类似于Eratosthenes筛法这里
            for(int j = i;j <= n;j+=i){
                phi[j] = phi[j]/i*(i-1);
            }
        }
    }       
}
   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 欧几里得GCD,扩展~ 
    欧几里德算法又称辗转相除法,用于计算两个整数a,b的最大公约数(greatest common divisor)。 
    扩展欧几里德算法是用来在已知a, b求解一组x,y,使它们满足贝祖等式: ax+by = gcd(a, b) =d(解一定存在,根据数论中的相关定理)。扩展欧几里德常用在求解模线性方程及方程组中。
ll gcd(ll a,ll b) {
    return b == 0 ? a : gcd(b, a % b);
}

void exgcd(ll a, ll b, ll &d, ll &x, ll &y) {
    if(!b) d=a,x=1,y=0;
    else exgcd(b, a % b, d, y, x),y -= x * (a / b);
}
   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 逆元 
    方程ax≡1(mod p),的解称为a关于模p的逆,当gcd(a,p)==1(即a,p互质)时,方程有唯一解,否则无解。 
    对于一些题目会要求把结果MOD一个数,通常是一个较大的质数,对于加减乘法通过同余定理可以直接拆开计算,但对于(a/b)%MOD这个式子,是不可以写成(a%MOD/b%MOD)%MOD的,但是可以写为(a*b^-1)%MOD,其中b^-1表示b的逆元。
ll getinv (ll a,ll p) {
    ll d, x, y;
    exgcd (a, p, d, x, y);
    return (x + p) % p == 0 ? p : (x + p) % p;
}
   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 中国剩余定理(CRT) ,扩展~

中国剩余定理给出了以下的一元线性同余方程组:

这里写图片描述 
假设整数m1,m2, ... ,mn两两互质,则对任意的整数:a1,a2, ... ,an,方程组 有解,即x,扩展剩余定理就是m1,m2···mn,这几个数不两两互质的情况

ll CRT(ll M){
    ll sum=0,tmp,v;
    for (int i=1;i<=cnt;i++){
        tmp=M/m[i];
        v=getInv(tmp,m[i]);
        sum=(sum+tmp*a[i]*v)%M;
    }
    return sum;
}

/*以下是ECRT*/

bool merge(ll &a1,ll &m1,ll a2,ll m2){
    ll c,d,x,a3,m3;
    c=a2-a1;d=__gcd(m1,m2);
    if (c%d!=0) return false;
    c=c/d;m1=m1/d;m2=m2/d;
    x=getinv(m1,m2);
    x=(x*c)%m2;
    x=x*(m1*d)+a1;
    m3=m1*m2*d;
    a3=(x%m3+m3)%m3;
    a1=a3;m1=m3;
    return true;
}
ll ECRT(){
    ll A=a[1],M=r[1];
    for (int i=2;i<=n;i++) //无解返回 -1
      if (!merge(A,M,a[i],r[i]))
        return -1;
    return (A%M+M)%M;
}
   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 错排公式 
    问题: 十本不同的书放在书架上。现重新摆放,使每本书都不在原来放的位置。有几种摆法? 
    这个问题推广一下,就是错排问题,是组合数学中的问题之一。考虑一个有n个元素的排列,若一个排列中所有的元素都不在自己原来的位置上,那么这样的排列就称为原排列的一个错排。 n个元素的错排数记为D(n)。 研究一个排列错排个数的问题,叫做错排问题或称为更列问题。
//dp[i] = (i - 1)*(dp[i - 1] + dp[i - 2]); i > 2
ll a = 0,b = 1,c;
for (int i = 3; i <= n; i++) {
    c = ((i - 1) * 1ll * (a + b)) % MOD;
    a = b;
    b = c;
}
printf("%lld\n",c);
   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • O(n) 求组合数 
    Ckn=nk+1kCk1n Cnk=n−k+1kCnk−1 
    从开始从左到右递推,注意爆int

C[0] = 1;
for(int i = 1; i <= n; i++) 
    C[i] = C[i - 1] * (n - i + 1) / i;
   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 卡特兰数列 
    h(n)=C(2n,n)/(n+1) (n=0,1,2,...) 
    h(n)=c(2n,n)-c(2n,n-1)(n=0,1,2,...) 
    C(m+n,n)−C(m+n,n−1)

  • 阶乘逆元

fac[0] = 1;
for (int i = 1; i <= maxn; i++) 
    fac[i] = mod(fac[i - 1] * i);
rfac[maxn] = qpow(fac[maxn],MOD - 2);
for (int i = maxn;i > 0; i--) 
    rfac[i - 1] = mod(rfac[i] * i);
   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

图论模板

  • 单源最短路spfa
const int maxn = 1e5 + 10;

vectorint,int> > E[maxn];

int inq[maxn],n,m;
ll dis[maxn];

queue<int> q;

void spfa() {
    for(int i = 0;i < maxn;i++) {
        dis[i] = 2000000000;
        inq[i] = 0;
    }
    dis[1] = 0;
    q.push(1);
    while(!q.empty()) {
        int t = q.front();
        q.pop();inq[t] = 0;
        for(int i = 0;i < E[t].size();i++) {
            int to = E[t][i].first;
            ll di = E[t][i].second;
            if(dis[to] > dis[t] + di) {
                dis[to] = dis[t] + di;
                if(!inq[to]) {
                    inq[to] = 1;
                    q.push(to);
                }
            }
        }
    }
}


//SLF优化:Small Label First 策略,设要加入的节点是j,队首元素为i,若dist(j) < dist(i),则将j插入队首,否则插入队尾

void spfa() {
    for (int i = 0; i < maxn; i++) dis[i] = INF;
    deque<int> q;
    dis[s] = 0;
    q.push_back(s);
    while (!q.empty()) {
        int from = q.front();
        q.pop_front();
        inq[from] = 0;
        for (int i = 0; i < E[from].size(); i++) {
            int to = E[from][i].first;
            int di = E[from][i].second;
            if(dis[to] > dis[from] + di) {
                dis[to] = dis[from] + di;
                if(inq[to] == 0) {
                    inq[to] = 1;
                    if(q.size() && dis[to] < dis[from]) {
                        q.push_front(to);
                    } else {
                        q.push_back(to);
                    }
                }
            }
        }
    }
}
   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 单源最短路 迪杰斯特拉 dijkstra 
    队列优化
const int maxn = 1e5 + 10;

vectorint,int> > E[maxn];

int n,m,dis[maxn];

priority_queueint,int> > q;

void dij() {
    for(int i = 0;i < maxn;++i) {
        dis[i] = 1e9;
    }
    dis[1] = 0;
    q.push(make_pair(0,1));
    while (!q.empty()) {
        int t = q.top().second;
        q.pop();
        for(int i = 0;i < E[t].size();++i) {
            int to = E[t][i].first;
            int di = E[t][i].second;
            if(dis[to] > dis[t] + di) {
                dis[to] = dis[t] + di;
                q.push(make_pair(-dis[to],to));
            }
        }
    }
}

   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

动态规划

  • 最长上升子序列
/*求LIS的长度*/

/*n方的写法,易写*/
int ans = 0;
for(int i = 1; i <= n; ++i) {
    scanf("%d", &num[i]);
    dp[i] = 1;
    for(int j = 1; j < i; ++j) {
        if(num[j] <= num[i]) {
            dp[i] = max(dp[i], dp[j] + 1);
        }
    }
    ans = max(ans, dp[i]);
}


/*手写二分,或者lower_brond*/

int binary(int x,int rr){
    int l = 0,r = rr,ans;
    while(l <= r){
        int mid = l + r >> 1;
        if(b[mid] >= x) ans = mid,r = mid  - 1;
        else l = mid + 1;
    }
    return ans;
}
int n;
for(int i = 1; i <= n;i++){
    cin>>a[i];
}
int len = 1;
b[1] = a[1];
for(int i = 2;i <= n;i++){
    if(a[i] > b[len]){
        b[++len] = a[i];
    }
    else {
        int t = binary(a[i],len);//也可以用c++自带的lower_pound,自写也可以
        b[t] = a[i];
    }
}
cout<
   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 背包dp
//01背包
for(int i = 1;i <= n;i++){
    for(int j = V;j >= w[i];j--){
        dp[j] = max(dp[j],dp[j-w[i]]+v[i]);
    }
}
//完全背包
for(int i = 0;i < n;i++){
    for(int j = w[i];j <= e-s;j++){
        dp[j] = min(dp[j],dp[j-w[i]]+v[i]);
    }
}
//多重背包
for(int i = 0;i < n;i++){
     for(int k = 0;k < b[i];k++){
         for(int j = n;j >= v[i];j--){
             dp[j] = max(dp[j],dp[j-v[i]]+w[i]);
         }
     }
}
//01背包 ,记录路径

#include
using namespace std;

const int N = 1e5 + 10;
int pre[N],dp[N],v[N],ans[N];

void p(int x){
    if(pre[x] == 0){
        cout<return;
    }
    p(pre[x]);
    cout<<' '<int main(){
    ios_base::sync_with_stdio(0);
    int n,m;cin>>n>>m;
    for(int i = 0;i < n;i++)cin>>v[i];
    for(int i = 0;i < N;i++)pre[i] = -1,dp[i] = -INF;
    sort(v,v+n);
    dp[0] = 0; //和01背包类似,因为是恰好装满,其他只要赋上负无穷
    for(int i = 0;i < n;i++){
        for(int j = m;j >= v[i];j--){
            if(dp[j] <= dp[j-v[i]]+1){
                dp[j] = dp[j-v[i]]+1;
                ans[j] = v[i];
                pre[j] = j - v[i];
            }
        }
    }
    if(dp[m] <= 0) cout<<"No Solution";
    else p(m);
    cout<return 0;
}




   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61

几何

Java

  • 大数基本操作
import java.util.Scanner;
import  java.math.BigInteger;

public class Main {
    public static void main(String[] args) {
        BigInteger[] a = new BigInteger[10100];
        a[0] = BigInteger.valueOf(1);
        for(int i = 1;i < 10100;i++) {
            a[i] = a[i-1].multiply(BigInteger.valueOf(i));
        }
        Scanner in = new Scanner(System.in);
        while (in.hasNextInt()) {
            int x = in.nextInt();
            System.out.println(a[x]);
        }
    }

}
   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

字符串

  • KMP

void getNext(string s) {
    int len = s.size();
    int k = -1,j = 0;
    Next[0] = k;
    while (j < len) { // 注意这里,因为这里要匹配多次
        if(k == -1 || s[k] == s[j]) {
            j++,k++;
            Next[j] = k;
        } else k = Next[k];
    }
}

//下面是优化的版本

void getNext(string s) {
    int len = s.size();
    int k = -1,j = 0;
    Next[0] = k;
    while (j < len) { // 注意这里,因为这里要匹配多次
        if(k == -1 || s[k] == s[j]) {
            j++,k++;
            if (s[j] == s[k]) {
                Next[j] = Next[k];
            } else {
                Next[j] = k;
            }
        } else k = Next[k];
    }
}


//匹配如下: 
        //如果s1是模式串   s2是匹配串  简单就是  s1是短的,s2是长的
        int res = 0;
        int lenS = s2.size();
        int j = 0,i = 0;
        while (i < lenS) {
            if (j == -1 || s2[i] == s1[j]) {
                i++,j++;
                if (j >= s1.size()) {//如果只匹配一次,直接break
                    res++;
                    j = Next[j]; // 注意
                }
            } else {
                j = Next[j];
            }
        }

   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • Trie树

#include 

using namespace std;

const int maxn = 1e6 + 10;
char S[maxn];

struct Trie{
    int next[26];
    int cnt;
    void init() {
        cnt = 0;
        memset(next, -1, sizeof next);
    }
}T[maxn];
int le;

void Insert(string s) {
    int p = 0;
    for (int i = 0; i < s.size(); i++) {
        int r = s[i] - 'a';
        if(T[p].next[r] == -1) {
            T[le].init();
            T[p].next[r] = le++;
        }
        p = T[p].next[r];
        T[p].cnt++;

    }
}

void query(string s) {
    int p = 0;
    for (int i = 0; i < s.size(); i++) {
        int r = s[i] - 'a';
        if(T[p].next[r] == -1) {
            cout<<0<return ;
        }
        p = T[p].next[r];
    }
    cout<int main() {
    ios_base::sync_with_stdio(0);
    int n;cin>>n;
    T[0].init();
    le = 1;
    for (int i = 0; i < n; i++) {
        string s;cin>>s;
        Insert(s);
    }
    int m;cin>>m;
    while (m--) {
        string s;cin>>s;
        query(s);
    }
    return 0;
}

你可能感兴趣的:(acm模板)