常用模板

  • 1、辗转相除法求最大公约数
int gcd(int a,int b)
{
    return b == 0?a:gcd(b,a%b);
}
  • 2、最大公约数
int lcm(int a,int b)
{
    return a/gcd(a,b)*b; //先除后乘防止a*b溢出
}
  • 3、拓展欧几里德算法
void extgcd(__int64 a,__int64 b,__int64 &x,__int64 &y)
{
    if (!b)
    {
        x = 1;
        y = 0;
    }
    else
    {
        extgcd(b,a%b,y,x);
        y -= x*(a/b);
    }
}
  • 4、求区间[m,n]内的素数( 埃氏筛选法)
int m = sqrt(n+0.5);
memset(vis,0,sizeof(vis));
for (int i = 2; i <= m; i++)
{
    if (!vis[i])
    {
        for (int j = i*i; j <= n; j += i)
        {
            vis[j] = 1;
        }
    }
}

版本二O(nloglogn)
int p = 0;
memset(is_prime,true,sizeof(is_prime));
is_prime[0] = is_prime[1] = false;
for(int i = 2; i <= MAX; i++)
{
    if (is_prime[i])
    {
        prime[p++] = i;
        for (int j = 2 * i; j <= MAX; j += i)
        {
            is_prime[j] = false;
        }
    }
}
  • 5、无平方因子的数
对于不超过√m 的所有素数p,筛选区间[n,m]内p² 的所有倍数
  • 6、快速乘
LL mod_multi(LL x,LL y,LL mod)   //拆分成y个x相加
{
    LL res = 0;
    while (y)
    {
        if (y&1)
        {
            res += x;
            while (res >= mod)  res -= mod;   
        }
        x += x;
        while (x >= mod)    x -= mod; 
        y >>= 1;
    }
    return res;
}
  • 7、快速幂
LL mod_pow(LL x,LL n,LL mod)
{
    LL res = 1;
    while (n > 0)
    {
        if (n&1)
        {
            res = mod_mulit(res,x,mod);
            // res = res*x%mod;
        }
        x = mod_multi(x,x,mod);
        //x = x*x%mod;
        n >>= 1;
    }
    return res;
}
  • 8、二分查找
// binsearch_min 返回key(可能有重复)第一次出现的下标,如无return -1

int binsearch_min(int * arr, int lef, int rig, int key)
{
    if(!arr)    return -1;
    int left = lef, right = rig;
    while(left < right)
    {
        int mid = left + ((right-left)>>1);
        if(arr[mid] < key)
        {
            left = mid+1;
        }
        else
        {
            right = mid;
        }
    }
    if(arr[left] == key)    return left;
    return -1;
}

// binsearch_max 返回key(可能有重复)最后一次出现的下标,如无return -1
int binsearch_max(int * arr, int lef, int rig, int key)
{
    if(!arr)    return -1;
    int left = lef, right = rig;
    while(left < right -1)
    {
        int mid = left + ((right-left)>>1);
        if(arr[mid] <= key)
        {
            left = mid;
        }
        else
        {
            right = mid;
        }
    }
    if(arr[right] == key) // 找max,先判断right
    {
        return right;
    }
    else if(arr[left] == key)
    {
        return left;
    }
    else
        return -1;
}
  • 9、并查集
void init()
{
    memset(father,0,sizeof(father));
    memset(rk,0,sizeof(rk));
    for (int i = 0; i <= N; i++)
    {
        father[i] = i;
    }
}

int find(int x)
{
    int r = x;
    while (father[r] != r)
    {
        r = father[r];
    }
    int i = x,j;
    while (i != r)           //路径压缩
    {
        j = father[i];
        father[i] = r;
        i = j;
    }
    return r;
}
/*
int find(int x)
{
    return father[x] == x?father[x]:father[x] = find(father[x]);
}
*/

void unite(int x,int y)
{
    int fx,fy;
    fx = find(x);
    fy = find(y);
    if (fx == fy)   return;
    if (rk[fx] < rk[fy])
    {
        father[fx] = fy;
    }
    else
    {
        father[fy] = fx;
        if (rk[fx] == rk[fy])
        {
            rk[fx]++;
        }
    }
}
  • 10、生成1~n的排列
void permutation(int n,int *A,int cur)
{
	if (cur == n)                   //递归边界 
	{
		for (int i = 0;i < n;i++)	printf("%d ",A[i]);
		printf("\n");
	}
	else for (int i = 1;i <= n;i++) //尝试在A[cur}中填各种整数i 
	{
		int ok = 1;
		for (int j = 0;j < cur;j++)	if (A[j] == i)	ok = 0;   //如果i已经在A[0]~A[cur-1]出现过,则不能再选 
		if (ok)
		{
			A[cur] = i;
			permutation(n,A,cur+1); //递归调用 
		}
	}
}
  • 11、生成可重集的排列
void permutation(int n,int *P,int *A,int cur) //输入数组P,并按字典序输出数组A各元素的所有全排列
{
    if (cur == n)
    {
        for (int i = 0; i < n; i++)	printf("%d ",A[i]);
        printf("\n");
    }
    else for (int i = 0; i < n; i++)
    {
        if (!i || P[i] != P[i-1])
        {
            int c1 = 0,c2 = 0;
            for (int j = 0; j < cur; j++)	if (A[j] == P[i])	c1++;
            for (int j = 0; j < n; j++)	if (P[i] == P[j])	c2++;
            if (c1 < c2)
            {
                A[cur] = P[i];
                permutation(n,P,A,cur+1);
            }
        }
    }
}
  • 12、强连通分量的targin算法
/* 寻找有向图强连通分量的tarjan算法
 * index表示的就是时间戳
 * scc_cnt 表示强连通分量的个数
 * belong[u] 表示结点u属于哪一个强连通分量
 * inst[u] 表示结点u是否仍然在栈中
 * st[] 和 top 分别表示栈和栈顶位置
 *index = scc_cnt = top = 0*/
void targin(int u)
{
    int v;
    dfn[u] = low[u] = ++index;
    st[++top] = u;
    inst[u] = 1;
    for (int i = head[u];i != -1;i = edge[i].next)
    {
        v = edge[i].v;
        if (!dfn[v])
        {
            targin(v);
            low[u] = min(low[u],low[v]);
        }
        else if (inst[v])
            low[u] = min(low[u],dfn[v]);
    }
    if (low[u] == dfn[u])
    {
        scc_cnt++;
        do
        {
            v = st[top--];
            inst[v] = 0;
            belong[v] = scc_cnt;
        }
        while (u != v);
    }
}
  • 13、SBT
/*
* tree[x].left   表示以 x 为节点的左儿子
* tree[x].right  表示以 x 为节点的右儿子
* tree[x].size   表示以 x 为根的节点的个数(大小)
*/
 
 
struct SBT
{
    int key,left,right,size;
} tree[10010];
int root = 0,top = 0;
 
void left_rot(int &x)         // 左旋
{
    int y = tree[x].right;
    if (!y) return;
    tree[x].right = tree[y].left;
    tree[y].left = x;
    tree[y].size = tree[x].size;
    tree[x].size = tree[tree[x].left].size + tree[tree[x].right].size + 1;
    x = y;
}
 
void right_rot(int &x)        //右旋
{
    int y = tree[x].left;
    if (!y) return;
    tree[x].left = tree[y].right;
    tree[y].right = x;
    tree[y].size = tree[x].size;
    tree[x].size = tree[tree[x].left].size + tree[tree[x].right].size + 1;
    x = y;
}
 
void maintain(int &x,bool flag)  //维护SBT状态
{
    if (!x) return;
    if (flag == false)           //左边
    {
        if(tree[tree[tree[x].left].left].size > tree[tree[x].right].size)//左孩子的左孩子大于右孩子
            right_rot(x);
        else if (tree[tree[tree[x].left].right].size > tree[tree[x].right].size) //左孩子的右孩子大于右孩子
        {
            left_rot(tree[x].left);
            right_rot(x);
        }
        else
            return;
    }
    else                       //右边
    {
        if(tree[tree[tree[x].right].right].size > tree[tree[x].left].size)//右孩子的右孩子大于左孩子
            left_rot(x);
        else if(tree[tree[tree[x].right].left].size > tree[tree[x].left].size) //右孩子的左孩子大于左孩子
        {
            right_rot(tree[x].right);
            left_rot(x);
        }
        else
            return;
    }
    maintain(tree[x].left,false);
    maintain(tree[x].right,true);
    maintain(x,true);
    maintain(x,false);
}
 
void insert(int &x,int key)  //插入
{
    if (x == 0)
    {
        x = ++top;
        tree[x].left = 0;
        tree[x].right = 0;
        tree[x].size = 1;
        tree[x].key = key;
    }
    else
    {
        tree[x].size++;
        if(key < tree[x].key)
            insert(tree[x].left,key);
        else
            insert(tree[x].right,key);//相同元素可插右子树
        maintain(x,key >= tree[x].key);
    }
}
 
int remove(int &x,int key)  //利用后继删除
{
    tree[x].size--;
    if(key > tree[x].key)
        remove(tree[x].right,key);
    else  if(key < tree[x].key)
        remove(tree[x].left,key);
    else  if(tree[x].left !=0 && !tree[x].right) //有左子树,无右子树
    {
        int tmp = x;
        x = tree[x].left;
        return tmp;
    }
    else if(!tree[x].left && tree[x].right != 0) //有右子树,无左子树
    {
        int tmp = x;
        x = tree[x].right;
        return tmp;
    }
    else if(!tree[x].left && !tree[x].right)    //无左右子树
    {
        int tmp = x;
        x = 0;
        return tmp;
    }
    else                                      //左右子树都有
    {
        int tmp = tree[x].right;
        while(tree[tmp].left)
            tmp = tree[tmp].left;
        tree[x].key = tree[temp].key;
        remove(tree[x].right,tree[tmp].key);
    }
}
 
int getmin(int x)    //求最小值
{
    while(tree[x].left)
        x = tree[x].left;
    return tree[x].key;
}
 
int getmax(int x)    //求最大值
{
    while(tree[x].right)
        x = tree[x].right;
    return tree[x].key;
}
 
int pred(int &x,int y,int key)   //前驱,y初始前驱,从0开始, 最终要的是返回值的key值
{
    if(x == 0)
        return y;
    if(key > tree[x].key)
        return pred(tree[x].right,x,key);
    else
        return pred(tree[x].left,y,key);
}
 
int succ(int &x,int y,int key)   //后继,同上
{
    if(x == 0)
        return y;
    if(key < tree[x].key)
        return succ(tree[x].left,x,key);
    else
        return succ(tree[x].right,y,key);
}
 
int select(int &x,int k)   //查找第k小的数
{
    int r = tree[tree[x].left].size + 1;
    if(r == k)
        return tree[x].key;
    else if(r < k)
        return select(tree[x].right,k - r);
    else
        return select(tree[x].left,k);
}
 
int rank(int &x,int key)   //key排第几
{
    if(key < tree[x].key)
    {
        return rank(tree[x].left,key);
    }
    else if(key > tree[x].key)
        return rank(tree[x].right,key) + tree[tree[x].left].size + 1;
    else
        return tree[tree[x].left].size + 1;
}
  • 14、关闭同步
ios::sync_with_stdio(false);
cin.tie(NULL);

 

  

 

 

  

 

posted @ 2016-09-11 10:55  zxzhang  阅读(387)  评论(0编辑  收藏  举报