萌新在線模板--keyboarder_zsq

好像馬上就要出去打鐵了QAQ,所以是不是要做個模板帶過去也玩一玩?
那就做吧。。。
標題就設爲萌新模板吧。。。各種萌新講解對吧。。。。

快速輸入

template <class T>
inline bool scan_d(T &ret)
{
    char c;
    int sgn;
    if(c=getchar(),c==EOF) return 0; //EOF
    while(c!='-'&&(c<'0'||c>'9')) c=getchar();
    sgn=(c=='-')?-1:1;
    ret=(c=='-')?0:(c-'0');
    while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
    ret*=sgn;
    return 1;
}
inline void out(int x)
{
    if(x>9) out(x/10);
    putchar(x%10+'0');
}

圖論

拓撲排序

最短路

最小生成樹

二分匹配

強連通Tarjan

最近公共祖先LCA

  1. 在線ST表,RMQ維護求LCA
// 注意Maxn 和 25  !!!
int deep[Maxn<<1], first[Maxn], tot, id[Maxn<<1];
int dp[Maxn<<1][25];         
void _DFS(int u, int dep, int fa){
    int v;
    id[++tot] = u;
    deep[tot] = dep;
    first[u] = tot;
    for(int i=head[u]; ~i; i = edge[i].nex){
        v = edge[i].v;
        if(v == fa) continue;
        _DFS(v, dep+1, u);
        id[++tot] = u;
        deep[tot] = dep;
    }
}
void ST(){
    for(int i=1;i<=tot;i++) dp[i][0] = i;
    for(int j=1;(1<<j) <= tot;j++){
        for(int i=1;i+(1<<j)-1<=tot;i++){
            int a = dp[i][j-1], b = dp[i+(1<<(j-1))][j-1];
            dp[i][j] = deep[a] < deep[b] ? a : b;
        }
    }
}
int RMQ(int Left, int Right){
    int k = 0;
    while(1<<(k+1) <= (Right - Left + 1)) k++;
    int a = dp[Left][k], b = dp[Right-(1<<k)+1][k];
    return deep[a] < deep[b] ? a : b;
}
int LCA(int u, int v){
    int x = first[u], y = first[v];
    if(x > y){
        x = x ^ y;
        y = x ^ y;
        x = x ^ y;
    }
    int res = RMQ(x, y);
    return id[res];
}
void solve(){
    tot = 0;
    _DFS(root, 1, -1);
    ST();
}

二分

  • 算法返回一個非遞減序列[first, last)中的第一個大於等於值val的位置。
lower_bound(ForwardIter first, ForwardIter last,const _Tp& val)
  • 算法返回一個非遞減序列[first, last)中第一個大於val的位置。
upper_bound(ForwardIter first, ForwardIter last, const _Tp& val)

其實如果是一個二分搜索答案,完全可以加一個判斷條件就是正確答案直接return正確答案,避免之後判斷,最後寫個return 特殊標記

  • 0000001111111,尋找一個滿足條件的最左;
int binary_find(int Left,int Right)  
{    
    while(Left<Right)  
    {  
        int mid=Left+(Right-Left)/2;  
        if(Judge(mid))  
            Right=mid;  
        else  
            Left=mid+1;  
    }  
    return Left;  
}  
  • 對於1111000000,尋找一個滿足條件的最右;
int binary_find(int Left,int Right)  
{
    while(Left<Right)  
    {
        int mid=Left+(Right-Left+1)/2;  
        if(Judge(mid))  
            Left=mid;  
        else  
            Right=mid-1;  
    }  
    return Left;  
}
  • 浮點數二分
    慘痛的教訓:浮點數最好轉化成整數再算,不然精度有問題。
double Solve(double L, double R)
{
    double M;
    for( int i = 0; i < 100; ++ i)
    {
        M = (L + R) / 2;
        if (Judge(M))
            R = M;
        else
            L = M;
    }
    return R;
}

三分

  • 凸性函數:
    Mid = (Left*2.0+Right)/3.0;
    Midmid = (Left + Right*2.0)/3.0;
    如果 cal(Mid) > cal(MidMid), 意味着 Mid 更靠近極值點 => Right = MidMid;
    否則, 意味着 MidMid 更靠近極值點 => Left = Mid;
#define g 9.8
#define PI 3.141592653589732384626433832795
const double eps = 1e-8;

double Cal(double x){
    /****計算需求****/

}
double SanfenTu(double Left, double Right){
    double Mid, Midmid, cMid, cMidmid;
    while(Left + eps < Right){
        Mid = (Left*2.0+Right)/3.0;
        Midmid = (Left + Right*2.0)/3.0;
        cMid = Cal(Mid);
        cMidmid = Cal(Midmid);
        if(cMid > cMidmid) Right = Midmid;
        else Left = Mid;
    }
    /***注意返回什麼**/
//    return Cal(Left);
//    
//    return Left;
}
  • 凹性函數:
    Mid=(Left*2.0 + Right)/3;
    Midmid=(Right*2.0 + Left)/3;
    如果 cal(Mid) > cal(MidMid) 意味着 MidMid 更靠近極值點 => Left = Mid;
    否則, 意味着 Mid 更靠近極值點 => Right = MidMid;
double Cal(double x){
    /****計算需求****/
}
double SanfenAo(double Left, double Right){
    double Mid, Midmid, cMid, cMidmid;
    while(Left + eps < Right){
        Mid = (Left*2.0 + Right) / 3;
        Midmid = (Right*2.0 + Left) / 3;
        cMid = Cal(Mid);
        cMidmid = Cal(Midmid);
        if(cMid > cMidmid) Left = Mid;
        else Right = Midmid;
    }
    /***注意返回什麼**/
//    return Cal(Left);
//    
//    return Left;
}

樹狀數組

線段樹


/*
線段樹模板
Author: Keyboarder_Zsq
Time: 2017/9/28/18:19
*/
const int Maxn = 1e5 + 10;      //線段樹節點個數
#define elem LL     //區間數據類型
#define Elem LL     //數值數據類型
#define GetMid (node[num].Left+node[num].Right)>>1
#define Lson num<<1
#define Rson num<<1|1
Elem v[Maxn];
struct Seg{
    elem Left, Right;
    Elem Sum;   //區間和
    Elem Lazy;  //和標記
    Elem Max;   //區間最大值
    Elem Min;   //區間最小值
}node[Maxn<<2];
Elem Mmax(Elem va, Elem vb){
    return va > vb ? va : vb;
}
Elem Mmin(Elem va, Elem vb){
    return va < vb ? va : vb;
}
Elem ADD(Elem va, Elem vb){
    return va + vb;
}
void Push_Up(int num){
    node[num].Max = Mmax(node[Lson].Max, node[Rson].Max);
    node[num].Min = Mmin(node[Lson].Min, node[Rson].Min);
    node[num].Sum = ADD(node[Lson].Sum, node[Rson].Sum);
}

void Push_Down(int num){
    if(node[num].Lazy){
        node[Lson].Lazy = node[Lson].Lazy + node[num].Lazy;
        node[Lson].Sum = node[Lson].Sum + node[num].Lazy * (node[Lson].Right - node[Lson].Left + 1);

        node[Rson].Lazy = node[Rson].Lazy + node[num].Lazy;
        node[Rson].Sum = node[Rson].Sum + node[num].Lazy * (node[Rson].Right - node[Rson].Left + 1);

        node[num].Lazy = 0;
    }
}
//建樹
void Build(int num, int Left, int Right){
    node[num].Left = Left;
    node[num].Right = Right;
////node[num].Lazy = 0;
    if(Left == Right){
////        node[num].Sum = node[num].Max = node[num].Min = v[Left];
////        scanf("%lld",&node[num].Sum);
//        node[num].Max = 0;
        return;
    }
    int Mid = GetMid;
    Build(Lson, Left, Mid);
    Build(Rson, Mid+1, Right);
    Push_Up(num);
}
//區間更新
void Update_Seg(int num, int s, int t, Elem val){
    if(node[num].Left >= s && node[num].Right <= t){
        node[num].Lazy = node[num].Lazy + val;
        node[num].Sum = node[num].Sum + val * (node[num].Right - node[num].Left + 1);
        return;
    }
    Push_Down(num);
    int Mid = GetMid;
    if(Mid >= t) Update_Seg(Lson, s, t, val);
    else if(Mid < s) Update_Seg(Rson, s, t, val);
    else{
        Update_Seg(Lson, s, Mid, val);
        Update_Seg(Rson, Mid+1, t, val);
    }
    Push_Up(num);
}
//區間求和
Elem Query_Sum(int num, int s, int t){
    if(node[num].Left >= s && node[num].Right <= t)
        return node[num].Sum;
    Push_Down(num);
    int Mid = GetMid;
    if(Mid >= t) return Query_Sum(Lson, s, t);
    else if(Mid < s) return Query_Sum(Rson, s, t);
    else{
        Elem x,y;
        x = Query_Sum(Lson, s, Mid);
        y = Query_Sum(Rson, Mid+1, t);
        return x + y;
    }
}
//點更新
void Update_One(int num, int pos, Elem val){
    if(node[num].Left == node[num].Right){
        if(node[num].Left == pos){
//            node[num].Sum = val;
//            node[num].Max = val;
//            node[num].Min = val;
        }
        return;
    }
    int Mid = GetMid;
    if(Mid >= pos) Update_One(Lson, pos, val);
    else Update_One(Rson, pos, val);
    Push_Up(num);
}
//區間求最大值
Elem Query_Max(int num, int s, int t){
    if(node[num].Left >= s && node[num].Right <= t)
        return node[num].Max;
    int Mid = GetMid;
    if(Mid >= t) return Query_Max(Lson, s, t);
    else if(Mid < s) return Query_Max(Rson, s, t);
    else{
        Elem x,y;
        x = Query_Max(Lson, s, Mid);
        y = Query_Max(Rson, Mid+1, t);
        return Mmax(x, y);
    }
}
//區間求最小值
Elem Query_Min(int num, int s, int t){
    if(node[num].Left >= s && node[num].Right <= t)
        return node[num].Min;
    int Mid = GetMid;
    if(Mid >= t) return Query_Min(Lson, s, t);
    else if(Mid < s) return Query_Min(Rson, s, t);
    else{
        Elem x,y;
        x = Query_Min(Lson, s, Mid);
        y = Query_Min(Rson, Mid+1, t);
        return Mmin(x, y);
    }
}

尺取

//尺取數組
    int Left, Right;
    Left = Right = 1;       //雙指針初始化
    while(Left <= N){
        //先讓右指針跑,並且保證右指針的情況都是合法的
        while(Right+1 <= N && Solution_Is_OK(Right+1)){
            Change_ADD();       //改變中間值,靠近約束條件
            Right++;            //如果(右指針+1)符合,右指針往後移
        }
        GetValue();             //得到需要求的最優值

        if(Right+1 == sz)       //break條件 具體看情況決定
            break;

        //由於添加(右指針+1)的位置會造成衝突,所以左指針往後移
        while(Left < sz && Right+1 < sz && Solution_Is_Not_OK(Right+1)){
            Change_Erase();      //改變中間值,變成符合條件
            Left++;              //如果(右指針+1)不符合,左指針往後移
        }
    }

組合數模板

const int N = 67;
LL C[N][N];
C[1][0] = C[1][1] = 1;
for (int i = 2; i < N; i++){
    C[i][0] = 1;
    for (int j = 1; j < N; j++){
        C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]);
    }
}

exgcd模板

int exgcd(int a,int b,int &x,int &y){
    if(b == 0){
        x = 1;
        y = 0;
        return a;
    }
    int d = exgcd(b, a%b, x, y);
    int tmp = x;
    x = y;
    y = tmp - a/b*y;
    return d;
}

exgcd求逆元模板

Elem inv[Maxn]; ///逆元
Elem extend_gcd(Elem a,Elem b,Elem &x,Elem &y){
    if( b == 0 ) {
        x = 1;
        y = 0;
        return a;
    }
    else{
        Elem x1,y1;
        Elem d = extend_gcd (b,a % b,x1,y1);
        x = y1;
        y= x1 - a / b * y1;
        return d;
    }
}
Elem mod_reverse(Elem a,Elem n)
{
    Elem x,y;
    Elem d=extend_gcd(a,n,x,y);
    if(d==1) return (x%n+n)%n;
    else return -1;
}
void init(){
    inv[0] = 0,inv[1]=1;
    for(int i=2;i<=10000;i++){
        inv[i] = mod_reverse(i,9973);
    }
}

exgcd求不定方程ax+by=gcd(a, b)的解

Author: keyboarder_zsq
Time: 2017/10/22 18:53

typedef int Elem;
Elem exgcd(Elem a , Elem b, Elem &x, Elem &y){
    if(b == 0){
        x = 1, y = 0;
        return a;
    }
    Elem gcd = exgcd(b, a%b, x, y);
    Elem temp = x;
    x = y;
    y = temp - a/b*y;
    return gcd;
}
//求方程 a*x + b*y = c 的 x 的最小整數解.
//先利用 exgcd 求 a*x + b*y = gcd(a, b) 的x, y的最小整數解。
//然後再乘上去就好了;
Elem Cal(Elem a, Elem b, Elem c){
    Elem x, y, k, t;
    Elem gcd = exgcd(a, b, x, y);

    if(c%gcd!=0) return -1; //不存在解
    x = x * c/gcd;          //由a*x + b*y = gcd(a, b) 轉化爲 a*x + b*y = c 的解
    k = b/gcd;              //約去c後原來b就變爲了b/gcd;
    if(k < 0) k = -k;       //如果b爲負數就去絕對值

    x = (x%k + k) % k;      //最小非負整數解
    if(x <= 0) x = x + k;   //最小正整數解

    y = (c - a * x)/b;      //如果對y還有要求,先求出y值在進行判斷

    while(y<0){
        x = x + k;
        y = (c - a * x)/b;
    }
    return x;
}

逆元預處理模板

typedef long long LL;
const int MAXN = 5e3+5;
const LL MOD = 1e9+7;
LL Inv[MAXN];
void Get_Inv()
{
    Inv[1] = 1;
    for(int i=2; i<MAXN; i++)
        Inv[i] = ( (MOD-MOD/i)*Inv[MOD%i] ) % MOD;
}

字符串hash模板

模板1. 字符串長度>=1e4/1e5 安全級別低/但是時間比較可觀
hash 函數可以理解爲:
hash[i]=(hash[i1]×p+s[i])%(264)
求區間: hash[L,R]=hash[R]hash[L1]p(RL+1)

安全指數:三星(所以並不是很安全)
取膜利用 ULL 自動取膜(省時間)
大致滿足字符串長度>1e4/1e5,因爲相對於方法2,這個時間小。

//ULL printf()輸出方式 %llu.
typedef unsigned long long ULL;
const int Maxn = 1e6 + 7;   // 字符串長度
const ULL p = 31;           // p 是字符串的種類
ULL f[Maxn], Has[Maxn];
char s1[Maxn], s2[Maxn];
//預處理 p的次數
void init(){
    f[0] = 1;
    for(int i=1;i<=1000000;i++) f[i] = f[i-1] * p;
}

//得到字符串區間 hash 值
ULL Get_Left_to_Right(int Left, int Right){
    return Has[Right] - Has[Left-1] * f[Right - Left + 1];
}

//用於 hash 單字符串
ULL Get_Hashval(char str[]){
    int len = strlen(str+1);
    ULL temp = 0;
    for(int i=1;i<=len;i++) temp = temp * p + str[i];
    return temp;
}
//對於一個字符串hash出 [1, pos] 的hash值
void _Hash(char str[]){
    Has[0] = 0;
    int len = strlen(str+1);
    for(int i=1;i<=len;i++) Has[i] = Has[i-1] * p + str[i];
}

模板2. 用於字符串長度<1e4/5e3的安全比較高/但是比較費時
hash[i]=(hash[i1]×p+idx(s[i]))%mod
求區間:
hash[L,R]=hash[R]hash[L1]p(RL+1)
取膜比較費時,注意時間.

const int Maxn = 1e4 + 10;
const LL p = 31;
const LL mod = 1e9 + 7;
char s1[Maxn], s2[Maxn*100];
LL h1[Maxn], h2[Maxn*100], f[Maxn*100];
void init(){
    h1[0] = h2[0] = 0;
    f[0] = 1;
    for(int i=1;i<=1000000;i++) f[i] = f[i-1] * p % mod;
}
LL idx(char x){
    return (long long)(x - 'A' + 1);
}

void Hash(char s[], LL has[]){
    int len = strlen(s+1);
    for(int i=1;i<=len;i++)
        has[i]=(has[i-1]*p+idx(s[i])) % mod;
}
LL get_L_to_R(int Left, int Right, LL has[]){
    return (has[Right] - has[Left-1]* f[Right - Left + 1] % mod + mod) % mod;
}

模板3.雙hash,太費時;
模板2加強版,具體打法參照模板2.
mod1和mod2
hash1[i]=(hash1[i-1]*p+idx(s[i]))%mod1;
hash2[i]=(hash2[i-1]*p+idx(s[i]))%mod2;
mod1一般取1e9+7,mod2一般取1e9+9爲什麼這麼取?
1000000007和1000000009是一對孿生素數,取它們,衝突的概率極低!
安全指數:五星!(非常穩!)(穩啊…穩T了…開玩笑)


打CF及一些在線比賽可以用的模板

矩陣相關

const int Maxn = 64;

struct Matrix{
    Matrix(){}
    Matrix(int R, int C, int M) : R(R), C(C), M(M){}

    void Clear()
    { memset(pData, 0, sizeof(pData)); }

    void init(int A, int B, int C){
        for(int i=1;i<Maxn;i++){
            pData[i][i-1] = A;
            pData[i][i] = B;
            pData[i][i+1] = C;
        }
    }

    Matrix operator + (Matrix& x) const
    {
        Matrix ans(R, C, M);
        for(int i=1;i<=R;i++)
            for(int j=1;j<=C;j++)
                ans.pData[i][j] = (pData[i][j] + x.pData[i][j]) % M;
        return ans;
    }
    Matrix operator * (Matrix& x) const
    {
        Matrix Tmp(R, x.C, M);
        Tmp.Clear();
        for(int k=1;k<=C;k++){
            for(int i=1;i<=Tmp.R;i++){
                for(int j=1;j<=Tmp.C;j++){
                    Tmp.pData[i][j] = (Tmp.pData[i][j] + pData[i][k] * x.pData[k][j] % M) % M;
                }
            }
        }
        return Tmp;
    }
    Matrix operator ^ (int x) const
    {
        Matrix ans(R, R, M), Tmp(R, R, M);
        memcpy(Tmp.pData, pData, sizeof(Tmp.pData));
        ans.Clear();
        for(int i=1;i<=ans.R;i++)
        { ans.pData[i][i] = 1; }
        while(x){
            if(x & 1) ans = ans * Tmp;
            x >>= 1;
            Tmp = Tmp * Tmp;
        }
        return ans;
    }

    int R, C, M;
    int pData[Maxn][Maxn];
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章