您的位置:首页 > 其它

ACM模板

2018-03-30 19:52 337 查看
      之前做过acm,总结出来了一些算法模板。这些是我在搞懂先自己写然后想大牛靠拢不断优化的结果,可能有些是大牛们的源代码,在此一并发出,希望对大家有所帮助,代码中可能有错,在此表示歉意。[cpp] view plain copy 动态规划模板  
处理求矩阵的最大子矩  
//************************************************************  
//求a
[m]的最大子矩阵  
///计算从某固定行开始起连续列b[i,j]动态规划求最大值  
int dp( const int *b,int m)  
{  
    int sum ,max,i;  
    sum=max=b[0];  
    for(i=1;i<m;i++)  
    {  
        if(sum>0)sum+=b[i];  
        else sum=b[i];  
        if(sum>max)max=sum;  
    }  
    return max;  
}  
  
//b[k]可以取到任意连续行的排列组合  
max=-999999999;   
for(i=0;i<n;i++)//控制具体哪一行开始  
{  
    memset(b,0,sizeof(b));  
    for(j=i;j<n;j++)//表示从第i行到最后n行中间每列累加得b[k]  
    {  
        for(k=0;k<m;k++)  
            b[k]+=a[j][k];  
        if(dp(b,m)>max) max=dp(b,m);  
    }  
}  
//************************************************************  
  
动态规划求最大面积  
//************************************************************  
 {  
  首先开辟数组a
,l
,r
  
////找出其左右区间比其大的区间长度  
        l[1]=1;    
        r
=n;    
       for (i=2; i<=n; ++i)    
        {    
           t=i;    
            while (t>1 && a[i]<=a[t-1]) t=l[t-1];    
            l[i]=t;    
        }    
        for (i=n-1; i>=1; --i)    
       {    
            t=i;    
            while (t<n && a[i]<=a[t+1]) t=r[t+1];    
            r[i]=t;    
        }   
        /////分别以每个小矩形的高度为高求大矩形面积,并找出其最大者  
        max=0;    
        for (i=1; i<=n; ++i)    
        {    
            if ((r[i]-l[i]+1)*a[i]>max) max=(r[i]-l[i]+1)*a[i];    
       }   
}  
//************************************************************  
  
最长公共子序列  
//*********************************************************  
//算法1:时间复杂度为O(N*M),空间复杂度为O(N*N)  
const int MAXN=1000;  
char str1[MAXN],str2[MAXN];  
int dp[MAXN][MAXN];  
  
int LCS1(char *str1,char *str2)  
{  
    int len1=strlen(str1);  
    int len2=strlen(str2);  
    int i,j;  
    memset(dp,0,sizeof(dp));  
    for(i=1;i<=len1;i++)  
    {  
        for(j=1;j<=len2;j++)  
        {  
            if(str1[i-1]==str2[j-1])  
                dp[i][j]=dp[i-1][j-1]+1;  
            else if(dp[i-1][j]>dp[i][j-1])  
                dp[i][j]=dp[i-1][j];  
            else dp[i][j]=dp[i][j-1];  
        }  
    }  
    return dp[len1][len2];  
}  
  
//===============================================//算法2:时间复杂度为O(N*M),空间复杂度为O(N)  
const int MAXN=1000;  
char str1[MAXN],str2[MAXN];  
int dp[2][MAXN];//采用滚动数组优化  
  
int LCS2(char *str1,char *str2)  
{  
    int len1=strlen(str1);  
    int len2=strlen(str2);  
    int i,j,k;  
    memset(dp,0,sizeof(dp));  
    for(i=1;i<=len1;i++)  
    {  
        k=i&1;  
        for(j=1;j<=len2;j++)  
        {  
            if(str1[i-1]==str2[j-1])  
                dp[k][j]=dp[k][j-1]+1;  
            else if(dp[k^1][j]>dp[k][j-1])  
                dp[k][j]=dp[k^1][j];  
            else dp[k][j]=dp[k][j-1];  
        }  
    }  
    return dp[k][len2];  
}  
//*********************************************************  
  
最长公共递增子序列  
//************************************************************  
 //其中a
,b
分别存放俩序列  
    memset(dp,0,sizeof(dp));  
    max=0;  
    for(i=0;i<n;i++)  
    {  
        k=0;  
        for(j=0;j<m;j++)  
        {  
            //////////////保证递增又保证找到最大  
            if(a[i]>b[j]&&dp[k]<dp[j])  
                k=j;      
            if(a[i]==b[j])  
                dp[j]=dp[k]+1;  
            if(max<dp[j])  
                max=dp[j];  
        }  
    }  
//************************************************************  
  
  
数塔问题  
//************************************************************  
//n,m分别表示行数列数  
void shuta(int n,int m)  
{  
    int i,j;  
    memset(data,0,sizeof(data));  
    memset(dp,0,sizeof(dp));      
    for(i=1;i<=n;i++)  
    {  
        for(j=1;j<=i;j++)  
        {  
            cin>>data[i][j];  
        }  
    }  
    for(j=1;j<=m;j++)  
        dp
[j]=data
[j];  
    for(i=n-1;i>=1;i--)  
    {  
        for(j=i;j>=1;j--)  
        {  
            dp[i][j]=max(dp[i+1][j]+data[i][j],dp[i+1][j+1]+data[i][j]);  
        }     
    }  
}  
//************************************************************  
  
最长递增子序列  
//求严格递增子序列的最长长度  
//************************************************************  
//算法1的时间复杂度为O(N*log(N))  
const int MAXN=1000;  
int data[MAXN];//存放原始数据  
int MaxV[MAXN];//MaxV[i]存放长度为i的严格递增子序列的最大值的最小值  
  
//二分查找返回MaxV中大于等于x的组靠左的下标  
int BinaryResearch(int x,int len)  
{  
    int mid,low=1,high=len;  
    while(low<=high)  
    {  
        mid=(low+high)>>1;  
        if(MaxV[mid]<x)  
            low=mid+1;  
        else high=mid-1;  
    }  
    return low;  
}  
//返回原序列中严格递增子序列的最长长度  
int LIS2(int n)  
{  
    int i,len=1;  
    MaxV[1]=data[0];  
    for(i=1;i<n;i++)  
    {  
        if(data[i]>MaxV[len])//比长度为len的子序列最大值大,直接加进末尾  
            MaxV[++len]=data[i];  
        else   
        {  
            int pos=BinaryResearch(data[i],len);  
            MaxV[pos]=data[i];  
        }  
    }  
    return len;  
}  
//===============================================  
//算法2的时间复杂度为O(N*N)  
int dp[MAXN];  
//返回原序列中严格递增子序列的最长长度  
int LIS1(int n)  
{  
    int i,j,lmax;  
    lmax=0;  
    for(i=0;i<n;i++)  
    {  
        dp[i]=1;  
        for(j=0;j<i;j++)  
        {  
            if(data[i]>data[j]&&dp[j]+1>dp[i])  
                dp[i]=dp[j]+1;  
        }  
        if(dp[i]>lmax)lmax=dp[i];  
    }  
    return lmax;  
}  
//************************************************************  
  
最大字段和  
//************************************************************  
void MSS(int n)  
{  
    int i;  
    int max=NINF;  
    memset(dp,0,sizeof(dp));  
    for(i=1;i<=n;i++)  
    {  
        if(dp[i-1]<=0)  
            dp[i]=data[i];  
        else dp[i]=dp[i-1]+data[i];  
        if(max<dp[i])  
            max=dp[i];  
    }  
    cout<<max<<endl;  
}  
//************************************************************  
  
多重背包  
//************************************************************  
int dp[100000+10];//视具体情况而定  
struct node  
{  
    int num,weight,value;//分别代表每种物品的数量、重量、价值  
}Good[15];//定义每个物品的结构体  
int Max_weight;//背包的载重量  
int max(int a,int b)  
<
ad8cd
li style="list-style-position:outside;border-style:none none none solid;border-left-width:3px;border-left-color:rgb(108,226,108);line-height:18px;background-color:rgb(248,248,248);margin-right:0px;margin-bottom:0px;padding:0px 3px 0px 10px;">{  
    return a<b?b:a;  
}  
void ZeroOnePack(int weight,int value,int lim)  
//对应01背包的求法  
{  
    for(int i=lim;i>=weight;i--)  
        dp[i]=max(dp[i],dp[i-weight]+value);  
}  
void CompletePack(int weight,int value,int lim)  
//对应完全背包的求法  
{  
    for(int i=weight;i<=lim;i++)  
        dp[i]=max(dp[i],dp[i-weight]+value);  
}  
void MultiplePack(int weight,int value,int amount,int lim)  
//选定物品后的多重背包的求法  
{  
    if(weight*amount>=lim)CompletePack(weight,value,lim);  
    else  
    {  
        for(int k=1;k<amount;)  
        {  
            ZeroOnePack(k*weight,k*value,lim);  
            amount-=k;  
            k<<=1;  
        }  
        ZeroOnePack(amount*weight,amount*value,lim);  
    }  
}  
void Solve(int n)  
//解决物品种类数为n的多重背包问题求法  
{  
    memset(dp,0,sizeof(dp));  
    for(int i=1;i<=n;i++)  
        MultiplePack(Good[i].weight,Good[i].value,Good[i].num,Max_weight);  
}  
//************************************************************  
  
  
  
  
  
数据结构          
单调队列  
const int MAXN=100000+10;  
int da[MAXN],Inc[MAXN],Dec[MAXN];  
int n,m,k,front1,rear1,front2,rear2;  
//维护双端单调队列,求da[]中满足m<=Max-Min<=k最长连续子序列  
int Queue()  
{  
    front1=0,rear1=-1,front2=0,rear2=-1;  
    int i,ans=0,start=0;  
    for(i=0;i<n;i++)  
    {  
        while(front1<=rear1&&da[Dec[rear1]]<=da[i])//保证Dec队列在start-i区间内的递减  
            rear1--;  
        Dec[++rear1]=i;  
        while(front2<=rear2&&da[Inc[rear2]]>=da[i])//保证inc队列在start-i区间内的递增  
            rear2--;  
        Inc[++rear2]=i;  
        while(da[Dec[front1]]-da[Inc[front2]]>k)  
        {  
            //保证区间左端点向后滑动一个长度  
            if(Dec[front1]-Inc[front2]<0)  
            {  
                start=Dec[front1]+1;  
                front1++;  
            }  
            else  
            {  
                start=Inc[front2]+1;  
                front2++;  
            }  
        }  
        //满足m<=Max-Min<=k  
        if(da[Dec[front1]]-da[Inc[front2]]>=m)  
        {  
            if(i-start+1>ans)  
                ans=i-start+1;  
        }  
    }  
    return ans;  
}  
  
并查集  
//*****************************************************************  
1.求父亲节点并压缩路径  
int par[MAX];  
int Get_par(int a)  
//查找a的父亲节点并压缩路径  
{  
    if(par[a]==a)  
        return par[a];  
    //注意语句的顺序  
    int pa=par[a];  
    par[a]=Get_par(par[a]);  
//  
    return par[a];  
}  
  
2.合并  
void Merge(int a,int b)  
//合并a,b  
{  
    int pa,pb;  
    pa=Get_par(a);  
    pb=Get_par(b);  
    par[pa]=pb;  
}  
//*****************************************************************  
  
线段树  
不带延迟更新的操作  
//************************************************************  
int da[MAXN];  
struct node   
{  
    int left,right,sum;//sum此处灵活处理  
}tree[MAXN*4];  
//1.建立以left,right为左右边界,将数组da中元素存储在首地址从1开始的线段树tree的叶节点上  
void Build( int id,int left,int right)  
{  
    tree[id].left=left;  
    tree[id].right=right;  
    if(left==right)  
    {  
        //tree[id].sum=da[left];//此处可以直接初始化为对应da[left]  
        return ;  
    }  
    else  
    {  
        int mid =(left+right)>>1;          
        Build(id<<1,left,mid);  
        Build((id<<1)|1,mid+1,right);  
        //tree[id].sum=tree[(id<<1)].sum+tree[(id<<1)|1].sum;  
   }  
}  
  
//2.在线段树的叶节点pos处加val  
void Updata(int id,int pos,int val)  
{  
    tree[id].sum+=val;  
    if(tree[id].left==tree[id].right&&tree[id].left==pos)  
    {  
        return ;  
    }  
    int mid=(tree[id].left+tree[id].right)>>1;  
    if(pos<=mid)   
        Updata(id<<1,pos,val);  
    else   
        Updata((id<<1)|1,pos,val);  
}  
  
//3.查询区间[left,right]上的和  
int Query(int id,int left,int right)  
{  
    if(tree[id].left==left&&tree[id].right==right)  
    {  
        return tree[id].sum;  
    }  
    int mid=(tree[id].left+tree[id].right)>>1;  
    if(right<=mid)  
        return Query(id<<1,left,right);  
    if(left>=mid+1)  
        return Query((id<<1)|1,left,right);  
    return Query(id<<1,left,mid)+Query((id<<1)|1,mid+1,right);  
}  
//************************************************************  
  
线段树的延迟更新  
//*****************************************************  
const int MAXN=100000+100;  
struct node   
{  
    int left,right,add;  
    int Max;  
}tree[MAXN*4];  
  
void build(int id, int left, int right)  
{  
    tree[id].add=0;  
    tree[id].left=left;  
    tree[id].right=right;  
    tree[id].Max=0;  
    if(left==right)  
    {  
        return ;  
    }  
    else  
    {  
        int mid=(left+right)>>1;          
        build(id<<1,left,mid);  
        build((id<<1)|1,mid+1,right);  
    }  
}  
  
void updata(int id,int left,int right,int adi)  
{  
    if(tree[id].left==left&&tree[id].right==right)  
    {  
        tree[id].add+=adi;  
        return ;  
    }  
    int mid=(tree[id].left+tree[id].right)>>1;  
    if(right<=mid)  
        updata(id<<1,left,right,adi);  
    else if(left>mid)  
        updata((id<<1)|1,left,right,adi);  
    else  
    {  
        updata(id<<1,left,mid,adi);  
        updata((id<<1)|1,mid+1,right,adi);  
    }  
    tree[id].Max=max(tree[id<<1].Max+tree[id<<1].add,tree[(id<<1)|1].Max+tree[(id<<1)|1].add);  
}  
  
int query(int id,int left,int right)  
{  
    if(tree[id].left==left&&tree[id].right==right)  
    {  
        return tree[id].Max+tree[id].add;  
    }  
    int mid=(tree[id].left+tree[id].right)>>1;  
    if(tree[id].add!=0)  
    {  
        updata(id<<1,tree[id].left,mid,tree[id].add);  
        updata((id<<1)|1,mid+1,tree[id].right,tree[id].add);  
        tree[id].Max=max(tree[id<<1].Max+tree[id<<1].add,tree[(id<<1)|1].Max+tree[(id<<1)|1].add);  
        tree[id].add=0;  
    }  
    if(right<=mid)  
        return query(id<<1,left,right);  
    else if(left>mid )  
        return query((id<<1)|1,left,right);  
    else   
    {  
        return max(query(id<<1,left,mid),query((id<<1)|1,mid+1,right));  
    }  
}  
//*****************************************************************  
  
RMQ问题的ST算法  
//*****************************************************************  
const int MAXN=50000+100;  
const int Mpow=16;//保证2^(Mpow)>MAXN即可  
int data[MAXN];  
int Maxdp[MAXN][Mpow];  
int Mindp[MAXN][Mpow];  
inline int Min(int a,int b)  
{  
    return a<b?a:b;  
}  
inline int Max(int a,int b)  
{  
    return a>b?a:b;  
}  
inline void init(int n)  
{  
    for(int i=1;i<=n;i++)  
    {  
        Mindp[i][0]=Maxdp[i][0]=data[i];  
    }  
}  
//预处理过程,时间复杂度为O(N*log(N))  
//ST算法求区间最值  
//dp[i][j]表示区间[i,i+2^j-1]最值  
//求dp[i][j]时将其分成dp[i][j-1],dp[i+2^(j-1)][j-1]  
//[i,i+2^j-1]=[i,i+2^(j-1)-1]+[i+2^(j-1),i+2^(j-1)+2^(j-1)-1]  
inline void Rmp_ST(int n)  
{  
    int l,s;  
    for(l=1;l<=16;l++)  
    {  
        for(s=1;s<=n;s++)  
        {  
            if(s+(1<<l)-1<=n)  
            {  
                Maxdp[s][l]=Max(Maxdp[s][l-1],Maxdp[s+(1<<(l-1))][l-1]);  
                Mindp[s][l]=Min(Mindp[s][l-1],Mindp[s+(1<<(l-1))][l-1]);  
            }  
        }  
    }  
}  
//查询[s,e]区间最值,下标从1-n  
//求一个最大的k,是k满足2^k<=e-s+1  
//原理:区间[s,e]=区间[s,s+2^k-1]+区间[e-2^k+1,e]  
//s<=e-2^k+1,s+2^k-1<=e保证刚好完全覆盖  
inline void query()  
{  
    int s,e,Min_ans,Max_ans;  
    scanf("%d%d",&s,&e);  
    int k=(int)(log(1.0*e-s+1)/log(2.0));  
    Min_ans=Min(Mindp[s][k],Mindp[e-(1<<(k))+1][k]);  
    Max_ans=Max(Maxdp[s][k],Maxdp[e-(1<<(k))+1][k]);  
    printf("%d\n",Max_ans-Min_ans);  
}  
//*****************************************************************  
  
一维树状数组  
//************************************************************  
const int MAXN=8000+100;  
int C[MAXN];  
int Lowbit[MAXN];  
//C[i] = a[i-lowbit(i)+1] + …+ a[i],下表从1开始  
//Lowbit[i]=i&(i^(i-1));或Lowbit[i]=i&(-i);   
//1.查询  
int QuerySum(int p)  
//查询原数组中下标1-p的元素的和   
{   
   int nSum=0;   
   while(p>0)   
   {    
      nSum+=C[p];   
      p-=Lowbit[p];   
   }   
    return nSum;   
}   
  
//2.修改+初始化  
void Modify(int p,int val)   
//原数组中下表为p的元素+val,导致C[]数组中部分元素值的改变  
{   
    while(p<=MAXN-10)   
   {   
      C[p]+=val;   
      p+=Lowbit[p];   
    }   
}   
//************************************************************  
  
二维树状数组  
//*****************************************************************  
1.修改  
void Add( int y, int x,int a)  
//原数组中下表为[y][x]的元素+a,导致C[][]数组中部分元素值的改变  
{  
    while( y <= s )  
    {   
        int tmpx = x;  
        while( tmpx <= s )  
        {  
            C[y][tmpx] += a;  
            tmpx += Lowbit[tmpx];  
        }  
        y += Lowbit[y];  
    }  
}  
2.查询  
int QuerySum( int y, int x)  
//查询第1行到第y行,第1列到第x列的和  
{  
    int nSum = 0;  
    while( y > 0 )   
    {  
        int tmpx = x;  
        while( tmpx > 0)   
        {  
            nSum += C[y][tmpx];  
            tmpx -= Lowbit[tmpx];  
        }  
        y -= Lowbit[y];  
    }  
    return nSum;  
}  
//*****************************************************************  
  
划分树  
//*****************************************************************  
const int MAXN=100010;  
int tree[30][MAXN];//表示每层每个位置的值  
int sorted[MAXN];//已经排序的数  
int toleft[30][MAXN];//toleft[p][i]表示第p层从1到i有多少个数分入左边  
  
//创建划分树  
//时间复杂度为O(N*log(N))  
void build(int l,int r,int dep)  
{  
    int i;  
    if(l==r)return;  
    int mid=(l+r)>>1;  
    int same=mid-l+1;//表示等于中间值而且被分入左边的个数  
    for(i=l;i<=r;i++)  
      if(tree[dep][i]<sorted[mid])  
         same--;  
    int lpos=l;  
    int rpos=mid+1;  
    for(i=l;i<=r;i++)  
    {  
        if(tree[dep][i]<sorted[mid])//比中间的数小,分入左边  
             tree[dep+1][lpos++]=tree[dep][i];  
        else if(tree[dep][i]==sorted[mid]&&same>0)  
        {  
            tree[dep+1][lpos++]=tree[dep][i];  
            same--;  
        }  
        else  //比中间值大分入右边  
            tree[dep+1][rpos++]=tree[dep][i];  
        toleft[dep][i]=toleft[dep][l-1]+lpos-l;//从1到i放左边的个数  
  
    }  
    build(l,mid,dep+1);  
    build(mid+1,r,dep+1);  
}  
  
//查询区间第k小的数,[L,R]是大区间,[l,r]是要查询的小区间  
//时间复杂度为O(log(N))  
int query(int L,int R,int l,int r,int dep,int k)  
{  
    if(l==r)return tree[dep][l];  
    int mid=(L+R)>>1;  
    int cnt=toleft[dep][r]-toleft[dep][l-1];//[l,r]中位于左边的个数  
    if(cnt>=k)  
    {  
        //L+要查询的区间前被放在左边的个数  
        int newl=L+toleft[dep][l-1]-toleft[dep][L-1];  
        //左端点加上查询区间会被放在左边的个数  
        int newr=newl+cnt-1;  
        return query(L,mid,newl,newr,dep+1,k);  
    }  
    else  
    {  
         int newr=r+toleft[dep][R]-toleft[dep][r];  
         int newl=newr-(r-l-cnt);  
         return query(mid+1,R,newl,newr,dep+1,k-cnt);  
    }  
}  
Init()  
{  
     memset(toleft,0,sizeof(toleft));    
     for(i=1;i<=n;i++)    
     {   
        scanf("%d",&tree[0][i]);   
         sorted[i]=tree[0][i];   
     }   
      sort(sorted+1,sorted+n+1);    
      build(1,n,0);   
}  
//*****************************************************************  
  
字符串匹配  
Manacher算法求最长回文子串  
//*****************************************************************  
const int MAXN=1000000+100;  
char str1[MAXN*2],str2[MAXN*2];//待处理字符串  
int num[MAXN*2];  
//将str1变成str2,如abab变成$#a#b#a#b#  
void init()  
{  
    int i,id;  
    str2[0]='$';  
    str2[1]='#';  
    for(i=0,id=2;str1[i];i++,id+=2)  
    {  
        str2[id]=str1[i];  
        str2[id+1]='#';  
    }  
    str2[id]=0;  
}  
//Manacher算法求最长回文子串,时间复杂度为O(N)  
int Manacher()  
{  
    int i,ans=0,MxR=0,pos=1;  
    for(i=1;str2[i];i++)  
    {  
        if(MxR>i)num[i]=num[pos*2-i]<(MxR-i)?num[pos*2-i]:(MxR-i);  
        else num[i]=1;  
        while(str2[i+num[i]]==str2[i-num[i]])  
            num[i]++;  
        if(num[i]+i>MxR)  
        {  
            MxR=num[i]+i;  
            pos=i;  
        }  
        if(ans<num[i])  
            ans=num[i];  
    }  
    return ans-1;  
}  
//*****************************************************************  
  
BF  
//*****************************************************************  
//BF算法查找str2是否是str1的子串,返回str2在str1中首元素的下标  
int  BF()  
{  
    int i,j,len1,len2;  
    len1=strlen(str1);  
    len2=strlen(str2);  
    i=0;j=0;  
    while(i<len1&&j<len2)  
    {  
        if(str1[i]==str2[j])  
        {  
            i++;  
            j++;  
        }  
        else  
        {  
            i=i-j+1;  
            j=0;  
        }  
    }  
    if(j==len2)  
        return i-j;  
    else   
        return -1;  
}  
//*****************************************************************  
  
  
KMP  
len % (len - next[len]) == 0,那么循环节的循环次数为len / (len - next[len]),否则为1  
//*****************************************************************  
char W[MAXN],T[MAXN];//W为模式串,T为主串  
int next[MAXN];  
//整个KMP算法时间复杂度为O(N+M)  
//KMP算法中计算next[]数组  
void getNext(char *p)  
{  
    int j,k,len=strlen(p);  
    j=0;  
    k=-1;  
    next[0]=-1;  
    while(j<len)  
    {  
        if(k==-1||p[j]==p[k])  
        {  
            next[++j]=++k;  
        }  
        else k=next[k];  
    }  
}  
//KMP算法统计模式串W在主串T中出现的次数  
int KMP_count(char *W,char *T)  
{  
    int i,wlen=strlen(W),tlen=strlen(T),j=0,ans=0;  
    getNext(W);  
    for(i=0;i<tlen;i++)  
    {  
        while(j>0&&T[i]!=W[j])  
          j=next[j];  
        if(W[j]==T[i])j++;  
        if(j==wlen)  
        {  
            ans++;  
            j=next[j];  
        }  
    }  
    return ans;  
}  
//返回模式串T在主串S中首次出现的位置  
//返回的位置是从0开始的,若没有找到返回-1。  
int KMP_Index(char *W,char *T)  
{  
    int i=0, j=0,wlen=strlen(W),tlen=strlen(T);  
    getNext(W);  
    while(i<tlen&&j<wlen)  
    {  
        if(j==-1||T[i]==W[j])  
        {  
            i++; j++;  
        }  
        else  
            j=next[j];  
    }  
    if(j==wlen)  
        return i-wlen;  
    else  
        return -1;  
}  
//*****************************************************************  
  
字符串的最小表示法  
//*****************************************************************  
//返回母串的最小子串的起始位置,返回值从1开始到strlen(str)  
int minpresent(char *str)  
{  
    int i,j,k,len=strlen(str);  
    i=0,j=1,k=0;  
    while(i<len&&j<len&&k<len)  
    {  
        if(str[(i+k)%len]==str[(j+k)%len])  
            k++;  
        else   
        {  
            if(str[(i+k)%len]>str[(j+k)%len])  
            i=i+k+1;  
            else   
            j=j+k+1;  
            if(i==j)j++;  
            k=0;  
        }  
    }  
    return ++i<++j?i:j;  
}  
//*****************************************************************  
  
字典树  
//************************************************************  
//定义字典树结构体  
struct Trie  
{  
    Trie* next[26];  
    int flag;  
};  
Trie *root;  
//初始化root  
void init()  
{  
    root=new Trie;  
    memset(root,0,sizeof(Trie));  
}  
//2.插入  
//将str插入以root为根节点的字典树中  
void insert(char *str)  
{  
    int len = strlen(str);  
    Trie *s = root;  
    for (int i = 0; i < len; i++)  
    {  
        if (s->next[str[i] - 'a'])  
            s = s->next[str[i] - 'a'];  
        else  
        {  
            Trie* t = new Trie;  
            memset(t, 0, sizeof (Trie));  
            s->next[str[i] - 'a'] = t;  
            s = t;  
        }  
    }  
    s->flag = 1;  
}  
//3.查找  
//查找字典树中是否有元素str  
int find(char *str)  
{  
    int len = strlen(str);  
    Trie *s = root;  
    for (int i = 0; i < len; i++)  
    {  
        if (s->next[str[i] - 'a'])  
            s = s->next[str[i] - 'a'];  
        else  
            return 0;  
    }  
    return s->flag;/////////////////////flag可能不标志为单词结尾  
}  
//5.释放内存空间  
//释放以root为根节点的字典树内存空间  
void del(Trie *root)  
{  
    Trie *s = root;  
    for (int i = 0; i < 26; i++)  
    {  
        if (s->next[i])  
            del(s->next[i]);  
    }  
    delete s;  
    s = NULL;  
}  
//*****************************************************************  
  
AC自动机模板  
//************************************************************  
const int kind = 26;//视具体情况改动  
struct node  
{  
    node *fail; //失败指针  
    node *next[kind]; //Tire每个节点的26个子节点(最多26个字母)  
    int count; //是否为该单词的最后一个节点  
    node()  
    { //构造函数初始化  
        fail=NULL;  
        count=0;  
        memset(next,NULL,sizeof(next));  
    }  
}*q[1000*255]; //队列方便用于bfs构造失败指针,大小应依据Tries图//节点个数而定  
int head,tail; //队列的头尾指针  
node *Root;  
//1.建立Tries  
void insert(char *str,node *root)  
//建立一颗以root为根节点的不带前缀指针的字典树  
{  
    node *p=root;  
    int i=0,index;  
    while(str[i])  
    {  
        index=str[i]-'A';//视具体情况改动  
        if(p->next[index]==NULL)   
            p->next[index]=new node();  
        p=p->next[index];  
        i++;  
    }  
    p->count=1;  
}  
//2.建立前缀指针,形成Tries图  
void build_ac_automation(node *root)  
//在建好的字典树上添加前缀指针,形成Tries图,即ac自动机  
{  
    int i;  
    root->fail=NULL;  
    q[head++]=root;  
    while(head!=tail)  
    {  
        node *temp=q[tail++];  
        node *p=NULL;  
        for(i=0;i<kind;i++)  
        {  
            if(temp->next[i]!=NULL)  
            {  
                if(temp==root)   
                    temp->next[i]->fail=root;  
                else  
                {  
                    p=temp->fail;  
                    while(p!=NULL)  
                    {  
                        if(p->next[i]!=NULL)  
                        {  
                            temp->next[i]->fail=p->next[i];  
                            break;  
                        }  
                        p=p->fail;  
                    }  
                    if(p==NULL)   
                        temp->next[i]->fail=root;  
                }  
                q[head++]=temp->next[i];  
            }  
        }  
    }  
}  
//3.查询母串  
int query(node *root,char *s)  
//有多少种模式串出现在母串str[]中  
{  
    int i=0,cnt=0,index,len=strlen(s);  
    node *p=root;  
    while(s[i])  
    {  
        index=s[i]-'A';//视具体情况改动  
        while(p->next[index]==NULL && p!=root)  
            p=p->fail;  
        p=p->next[index];  
        p=(p==NULL)?root:p;  
        node *temp=p;  
        while(temp!=root&&temp->count)  
        {  
            cnt+=temp->count;  
            temp->count=0;  
            temp=temp->fail;  
        }     
        i++;  
    }  
    return cnt;  
}  
//4.初始化  
void init()  
{  
    head=tail=0;  
    Root=new node;  
}  
//************************************************************  
  
后缀数组  
//*****************************************************************  
const int MAXN=100000+100;  
char str[MAXN];//待处理字符串  
int sa[MAXN];//求得的后缀数组  
int wa[MAXN],wb[MAXN],wv[MAXN],wh[MAXN];  
int cmp(int *r,int a,int b,int l)  
{  
    return r[a]==r[b]&&r[a+l]==r[b+l];  
}  
//求后缀数组sa[],下标1到n-1(此处n=strlen(str)+1)有效后缀  
//将str的n个后缀从小到大进行排序之后把排好序的后缀的开头位置顺次放入sa中。  
//保证Suffix(sa[i])<Suffix(sa[i+1])  
//1<=i<n,sa[0]存放人为添加在末尾的那个最小的后缀  
//倍增算法的时间复杂度为O(nlogn)  
//倍增算法的空间复杂度都是O(n)  
void da(char *r,int *sa,int n,int m)  
{  
    int i,j,p,*x=wa,*y=wb,*t;  
    for(i=0;i<m;i++) wh[i]=0;  
    for(i=0;i<n;i++) wh[x[i]=r[i]]++;  
    for(i=1;i<m;i++) wh[i]+=wh[i-1];  
    for(i=n-1;i>=0;i--) sa[--wh[x[i]]]=i;  
    for(j=1,p=1;p<n;j*=2,m=p)  
    {  
        for(p=0,i=n-j;i<n;i++) y[p++]=i;  
        for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;  
        for(i=0;i<n;i++) wv[i]=x[y[i]];  
        for(i=0;i<m;i++) wh[i]=0;  
        for(i=0;i<n;i++) wh[wv[i]]++;  
        for(i=1;i<m;i++) wh[i]+=wh[i-1];  
        for(i=n-1;i>=0;i--) sa[--wh[wv[i]]]=y[i];  
        for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)  
            x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;  
    }  
    return;  
}  
  
int rank[MAXN],height[MAXN];  
//定义height[i]=suffix(sa[i-1])和suffix(sa[i])的最长公  
//共前缀,也就是排名相邻的两个后缀的最长公共前缀  
//任意两个起始位置为i,j(假设rank[i]<rank[j])的后缀的最长公共前缀  
//为height[rank[i]+1]、height[rank[i]+2]…height[rank[j]]的最小值  
void calheight(char *r,int *sa,int n)  
{  
    int i,j,k=0;  
    for(i=1;i<=n;i++) rank[sa[i]]=i;  
    for(i=0;i<n;height[rank[i++]]=k)  
        for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);  
        return;  
}  
  
//求不可重叠最长重复子串  
//先二分答案,把题目变成判定性问题:判断是否  
//存在两个长度为k 的子串是相同的,且不重叠  
//时间复杂度为O(N*log(N))  
int Bin_Solve(int n)  
{  
    int i,Minlen,Maxlen,midlen,lowid,highid;  
    bool flag;  
    Minlen=0,Maxlen=n/2;  
    while(Minlen<=Maxlen)//二分重复字串的长度  
    {  
        midlen=(Minlen+Maxlen)/2;  
        lowid=n+1,highid=0;  
        flag=false;  
        for(i=1;i<=n&&!flag;i++)//此处i表示排名  
        {  
            if (height[i]<midlen)lowid=highid=sa[i];//中间有一个的长度不大于midlen,就断开了  
            //即说明前面的和后面的最长公共前缀不可能大于等于miflen  
            else if(height[i]>=midlen)//长度大于等于midlen  
            {  
                lowid=min(lowid,sa[i]);  
                highid=max(highid,sa[i]);  
                if(highid-lowid>=midlen)//且不重叠  
                    flag=true;  
            }  
        }  
        if(flag)Minlen=midlen+1;  
        else Maxlen=midlen-1;  
    }  
    return Maxlen<4?0:Maxlen+1;  
}  
//*****************************************************************  
  
  
               
                 4.图论  
邻接表建图  
//*****************************************************  
const int MAXN=1000+100;  
const int INF = 0x3f3f3f3f;  
  
int head[MAXN];  
int dis[MAXN];  
bool visited[MAXN];  
int qq[MAXN];//模拟队列  
struct node  
{  
    int to;  
    int next;  
}Edg[20000+100];  
int n,m,tot;  
  
void init()  
{  
    tot=0;  
    memset(head,-1,sizeof(head));  
}  
  
void add(int a,int b)  
{  
    Edg[tot].to=b;  
    Edg[tot].next=head[a];  
    head[a]=tot++;  
}  
  
void BFS(int s)  
{  
    //queue<int>qq;  
    //qq.push(s);  
    int front,rear;  
     front=rear=0;       
    qq[front++]=s;  
    int now,i,to;  
    for(i=1;i<=n;i++)  
    {  
        if(i!=s)dis[i]=INF;  
        else dis[i]=0;  
    }  
    visited[s]=true;  
    while(rear<front)  
    {  
        //now=qq.front();  
        //qq.pop();  
        now=qq[rear++];  
        for(i=head[now];i!=-1;i=Edg[i].next)  
        {  
            to=Edg[i].to;  
            if(to==now||visited[to])continue;  
            dis[to]=dis[now]+1;  
            //qq.push(to);  
            qq[front++]=to;  
            visited[to]=true;  
        }  
    }  
}  
//*****************************************************  
  
  
  
二分图:  
模板一:匈牙利算法  
//************************************************************  
//二分图匹配(匈牙利算法的DFS实现)  
//初始化:g[][]两边顶点的划分情况  
//建立g[i][j]表示i->j的有向边就可以了,是左边向右边的匹配  
//g没有边相连则初始化为0  
//uN是匹配左边的顶点数,vN是匹配右边的顶点数  
//调用:res=hungary();输出最大匹配数  
//优点:适用于稠密图,DFS找增广路,实现简洁易于理解  
//时间复杂度:O(VE)  
//************************************************************  
//顶点编号从0开始的  
const int MAXN=510;  
int uN,vN;//u,v数目  
int g[MAXN][MAXN];  
int linker[MAXN];  
bool visited[MAXN];  
bool dfs(int u)//从左边开始找增广路径  
{  
    int v;  
    for(v=0;v<vN;v++)//这个顶点编号从0开始,若要从1开始需要修改  
      if(g[u][v]&&!visited[v])  
      {  
          visited[v]=true;  
          if(linker[v]==-1||dfs(linker[v]))  
          {//找增广路,反向  
              linker[v]=u;  
              return true;  
          }  
      }  
    return false;//这个不要忘了,经常忘记这句  
}  
int hungary()  
{  
    int res=0;  
    int u;  
    memset(linker,-1,sizeof(linker));  
    for(u=0;u<uN;u++)  
    {  
        memset(visited,0,sizeof(visited));  
        if(dfs(u)) res++;  
    }  
    return res;  
}  
//****************************************************  
  
  
最小生成树的Kruskal算法  
//************************************************************  
//带权值的无向图的最小生成树的Kruskal算法  
int id[maxm];//id[]存放边的下标,从[0-m-1]  
int eu[maxm],ev[maxm],ew[maxm];//依次存放无向边的两顶点和权值  
int n,m;//n为顶点数,m为边数  
int par[maxn];//并查集中存放顶点的数组  
int cmp( const int &i , const int &j)   
{   
    return ew[i]<ew[j];  
}  
int Get_Par( int x)  
{  
    if( par[x]==x)  
        return par[x];  
    par[x]=Get_Par(par[x]) ;  
    return par[x] ;   
}  
int Kruskal( )  
{  
    int ret=0, i , j , p ;  
    for(i=1;i<=n;i++)  
        par[i]=i; // node [ 1 . . n ]  
    for(i=0;i<m;i++)  
        id[i]=i ; // ew [ 0 . .m.1]  
    std::sort(id,id+m,cmp) ;  
    for(j=-1,i=1;i<n;i++)  
    {  
        while(p=id[++j],Get_Par(eu[p])==Get_Par(ev[p]));  
        ret+=ew[p];  
        par[Get_Par(ev[p])]=Get_Par(eu[p]) ;  
    }  
    return ret;  
}  
//************************************************************  
  
Dijkstra算法  
//************************************************************  
#define INF 0x3f3f3f3f  
#define Max 155  
int n;//表示顶点数目  
int dis[Max];//dis数组表示源点到各点的距离  
int g[Max][Max];//用邻接矩阵g[][]存放图的边  
bool visited[Max];//标记原点到该点的最短距离是否找到  
//开始应初始化memset(g, INF, sizeof(g));  
void Dijkstra(int start)  
{  
    int temp,k,i,j;  
    memset(visited,false,sizeof(visited));  
    for(i=1;i<=n;++i)  
        dis[i]=g[start][i];  
    dis[start]=0;  
    visited[start]=1;  
    for(i=1;i<=n;++i)  
    {  
        temp=INF;  
        for(int j=1;j<=n;++j)  
            if(!visited[j]&&temp>dis[j])  
                temp=dis[k=j];  
        if(temp==INF)break;  
        visited[k]=1;  
        for(j=1;j<=n;++j)  
            if(!visited[j]&&dis[j]>dis[k]+g[k][j])  
                dis[j]=dis[k]+g[k][j];  
    }  
}  
//************************************************************  
  
flyod算法  
//*****************************************************************  
int const Max=1001;   
int a[Max][Max];//存放边的权值  
int b[Max];//存放顶点的权值  
int nex[Max][Max]; //next[i][j]用来保存i-->j的最短路径中i的最优后即最近的顶点  
int N;   
void floyd()  
//flyod算法求个顶点间的最短路径长度并记录路径  
{  
    int i,j,k,fee;   
      
    for(i=1;i<=N;i++)  
        for(j=1;j<=N;j++)  
            nex[i][j]=j;   
          
  
        for(k=1;k<=N;k++)  
        {  
            for(i=1;i<=N;i++)  
            {  
                if(i==k||a[i][k]==-1)  
                    continue;  
                for(j=1;j<=N;j++)  
                {  
                    if(a[k][j]==-1||j==k)  
                        continue;   
                    fee = a[i][k]+a[k][j]+b[k];   
                    if(a[i][j]==-1||a[i][j]>fee)  
                    {  
                        a[i][j]=fee;   
                        nex[i][j]=nex[i][k];   
                    }  
                    //选择字典序小的路径  
                    else if(a[i][j]==fee)  
                    {  
                        if(nex[i][j]>nex[i][k])  
                            nex[i][j]=nex[i][k];  
                    }  
                }  
            }  
        }  
}  
  
void path(int i, int j)  
//递归输出最短路径  
{  
    if(j==nex[i][j])  
    {  
        printf("%d-->%d\n",i,j);   
    }  
    else   
    {  
        printf("%d-->",i);   
        path(nex[i][j],j);    
    }  
}  
//*****************************************************************  
  
  
  
            数论  
矩阵快速幂  
//*****************************************************  
//origin存放需计算的矩阵,res存放答案矩阵  
//最终答案为res.a[1][0](对应f
)  
struct matrix  
{  
    __int64 a[2][2];  
};  
matrix origin,res;  
//将res初始化为初始条件矩阵,人为输入关系递推矩阵origin  
void init()  
{  
    origin.a[0][0]=1,origin.a[1][0]=origin.a[0][1]=1,origin.a[1][1]=0;  
    res.a[0][0]=1,res.a[0][1]=res.a[1][0]=res.a[1][1]=0;  
}  
//直接将2个矩阵相乘x*y,返回计算后的矩阵  
matrix multiply(matrix &x,matrix &y,__int64 MOD)  
{  
    matrix temp;  
    memset(temp.a,0,sizeof(temp.a));  
    for(int i=0;i<2;i++)  
    {  
        for(int j=0;j<2;j++)  
        {  
            for(int k=0;k<2;k++)  
            {  
                temp.a[i][j]+=x.a[i][k]*y.a[k][j];  
                temp.a[i][j]%=MOD;  
            }  
        }  
    }  
    return temp;  
}  
//矩阵快速幂的计算,矩阵的n次幂,每个中间结果对MOD取模  
void calc(matrix &origin,matrix &res,__int64 n,__int64 MOD)  
{  
    while(n)  
    {  
        if(n&1)  
            res=multiply(origin,res,MOD);  
        n>>=1;  
        origin=multiply(origin,origin,MOD);  
    }  
}  
//*****************************************************  
  
快速幂  
A^B %C=A^( B%phi(C)+phi(C) ) %C     B>=phi(C)  
//************************************************************  
//快速幂x^n%mod的计算  
__int64 optimized_pow_n(__int64 x, __int64 n)  
{  
    __int64  pw = 1;  
    while (n > 0)  
    {  
        if (n & 1)         
            pw *= x;  
         pw=pw%mod;  
        x *= x;  
         x=x%mod;  
        n >>= 1;       
    }  
    return pw;  
}  
//************************************************************  
  
三分法求凹凸函数的极值点  
//*****************************************************  
//当需要求某凸性或凹形函数的极值,通过函数本身表达式并不容易求解时,就可以用三分法不断逼近求解  
double mid, midmid;  
while ( low + eps < high )  
{  
    mid = (low + high) / 2;  
    midmid = (mid + high ) / 2;  
    double cmid = cal(mid);  
    double cmidmid = cal(midmid);  
    if ( cmid > cmidmid )   
            high = midmid;  
    else   
        low = mid;  
}  
//*****************************************************  
  
普通母函数  
//*****************************************************  
//普通母函数,求组合数。  
int n,sum;//n表示物品种类数,sum为在[1,sum]范围类求每个价值的组合数(不排列)  
int num[100+10],value[100+10];//num[]存放该种类对应的个数,value[]存放该种类对应的价值  
int a[10000+100];  
int b[10000+100];  
void Generating_function()  
{  
    int i,j,k;  
    memset(a,0,sizeof(a));  
    memset(b,0,sizeof(b));  
    a[0]=1;  
    for(i=1;i<=n;i++)  
    {  
        for(j=0;j<=sum;j++)  
        {  
            for(k=0;k<=num[i]&&k*value[i]+j<=sum;k++)  
            {  
                b[k*value[i]+j]+=a[j];  
                b[k*value[i]+j]%=10000;  
            }  
        }  
        memcpy(a,b,sizeof(b));  
        memset(b,0,sizeof(b));  
    }  
}  
//*****************************************************  
  
最大公约数  
//*****************************************************  
//求a,b的最大公约数  
LL Gcd(LL a,LL b)  
{  
    return b==0?a:Gcd(b,a%b);   
}   
//*****************************************************  
  
  
  
  
  
  
  
  
  
  
  
  
计算几何  
  
//求不共线三点的外接圆,利用圆心到三点距离相等联立方程求得  
point GetCentre(point a,point b,point c)  
{  
    double a1=b.x-a.x,b1=b.y-a.y,c1=(a1*a1+b1*b1)/2;  
    double a2=c.x-a.x,b2=c.y-a.y,c2=(a2*a2+b2*b2)/2;  
    double d=a1*b2-a2*b1;  
    point ret;  
    ret.x=a.x+(c1*b2-c2*b1)/d;  
    ret.y=a.y+(a1*c2-a2*c1)/d;  
    return ret;  
}  
  
  
头文件及宏定义  
#include<iostream>  
#include<sstream>  
#include<fstream>  
#include<vector>  
#include<list>  
#include<deque>  
#include<queue>  
#include<stack>  
#include<map>  
#include<set>  
#include<bitset>  
#include<algorithm>  
#include<cstdio>  
#include<cstdlib>  
#include<cstring>  
#include<cctype>  
#include<cmath>  
#include<ctime>  
#include <numeric>   
using namespace std;  
const double eps(1e-8);  
const int INF = 0x3f3f3f3f;  
//优先级队列的两种定义方式  
struct cmp//对应大顶堆  
{  
    bool operator()(int a,int b)  
    {  
        return a<b;  
    }  
};  
priority_queue<int,vector<int>,cmp>Q;  
  
struct node  
{  
    int id;  
    bool operator < (const node& b)const   
    {  
        return id>b.id;  
    }  
};  
priority_queue<node>Q;  
  
  
//set,multiset用法  
struct cmp  
{  
     bool operator ()(const node &a,const node &b)const   
     {  
        return a.nam<b.nam;//从小到大排序  
     }  
};  
multiset<node,cmp>MulSet;//存放未处理 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: