OI算法复习

搜集一些算法,赛前背一背有好处的

转自各大网站

 

前排感谢:hzwer、风了咕凉

前辈。。。Orz

 

快速读入:

1 int read()
2 {
3     int x=0,f=1;char ch=getchar();
4     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
5     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
6     return x*f;
7 }

 

经典快排:虽说C++直接sort就好了。。。

 1 #include <iostream>
 2  
 3 using namespace std;
 4  
 5 void Qsort(int a[], int low, int high)
 6 {
 7     if(low >= high)
 8         return;
 9     int first = low;
10     int last = high;
11     int key = a[first];
12     while(first < last)
13     {
14         while(first < last && a[last] >= key)
15             --last;
16         a[first] = a[last];
17         while(first < last && a[first] <= key)
18             ++first;
19          a[last] = a[first];
20     }
21     a[first] = key;
22     Qsort(a, low, first-1);
23     Qsort(a, first+1, high);
24 }

 

归并排序:

 1 template <typename T>
 2 void MergeSort (T data[], int size)
 3 {
 4     if ( size>1 )
 5     {
 6         //预处理
 7         int mid=size/2;
 8         int numOfleft=mid;
 9         int numOfright=size-mid;
10         T* left=new T[numOfleft];
11         T* right=new T[numOfright];
12         //
13         std::copy(data, data+numOfleft, left);
14         std::copy(data+numOfleft, data+size, right);
15         MergeSort(left, numOfleft);
16         MergeSort(right, numOfright);
17         //
18         std::merge(left, left+numOfleft, right, right+numOfright, data);
19         //清理
20         delete[] left;
21         delete[] right;
22     }
23 }

堆排:

 1 template <typename T>
 2 void heap_down (T data[], int i, const int& size)
 3 {
 4     int p=i*2+1;
 5     while ( p<size )
 6     {
 7         if ( p+1<size )
 8         {
 9             if ( data[p]<data[p+1] )
10                 ++p;
11         }
12         if ( data[i]<data[p] )
13         {
14             std::swap(data[p], data[i]);
15             i=p;
16             p=i*2+1;
17         }
18         else
19             break;
20     }
21 }
 1 template <typename T>
 2 void HeapSort (T data[], int size)
 3 {
 4     int i;
 5     for (i=(size-1)/2; i>=0; --i)
 6         heap_down(data, i, size);
 7     for (i=size-1; i>0; --i)
 8     {
 9         std::swap(data[0], data[i]);
10         heap_down(data, 0, i);
11     }
12 }

拓扑排序:

 1 #include<iostream>
 2 #include<cstdio>
 3 using namespace std;
 4 
 5 struct Edge
 6 {
 7     int to,next;
 8 }E[100001];
 9 int head[100001],r[100001],s[100001];
10 int node=0;
11 
12 int n;
13 
14 void insert(int u,int v)
15 {
16     E[++node]=(Edge){v,head[u]};
17     head[u]=node;
18     r[v]++;
19 }
20 
21 void topsort()
22 {
23     int t=1,top=0;
24     for(int i=1;i<=n;i++)
25         if(!r[i])
26         {
27             s[++top]=i;
28         }
29     while(t<=top)
30     {
31         int x=s[t++];
32         for(int i=head[x];i;i=E[i].next)
33         {
34             r[E[i].to]--;
35             if(!r[E[i].to])
36             {
37                 s[++top]=E[i].to;
38             }
39         }
40     }
41 }

 

kahn算法(NOIP2013车站分级为例子)纯过程形式:

 1 #include<iostream>
 2 #include<cstring>
 3 using namespace std;
 4 
 5 const int MAXN=1000+10;
 6 int n,m,ans=0;
 7 int B[MAXN]={0},R[MAXN]={0},SK[MAXN]={0};//R储存入度  SK储存入度为0的点
 8 bool A[MAXN]={0},F[MAXN]={0},E[MAXN][MAXN]={0};//F判断点是否已被访问  E判断两点是否存在边
 9 
10 int main()
11 {
12     /*cin>>n>>m;
13     for(int i=1;i<=m;i++)
14     {
15         int s;
16         memset(A,0,sizeof(A));
17         cin>>s;
18         for(int j=1;j<=s;j++)
19         {
20             cin>>B[j];
21             A[B[j]]=1;
22         }
23         for(int j=B[1];j<=B[s];j++)
24             if(!A[j])
25                 for(int k=1;k<=s;k++)
26                     if(!E[j][B[k]])
27                     {
28                         E[j][B[k]]=1;
29                         R[B[k]]++;
30                     }
31     }*///初始化
32     int top;
33     while(1)
34     {
35         top=0;
36         for(int i=1;i<=n;i++)//遍历n个点
37             if(!R[i]&&!F[i])//如果入度为0且没有被访问过,则加入SK数组
38             {
39                 SK[++top]=i;//加入SK数组
40                 F[i]=1;//i点已被访问
41             }
42         if(top==0)break;//如果所有的点都被访问则跳出
43         for(int i=1;i<=top;i++)
44             for(int j=1;j<=n;j++)
45                 if(E[SK[i]][j])//判断是否有边
46                 {
47                     E[SK[i]][j]=0;//将边移除
48                     R[j]--;//入度-1
49                 }
50         ans++;
51     }
52     cout<<ans<<endl;
53     return 0;
54 }

 

并查集:

1 int find(int x)
2 {
3     while(f[x]!=0) x=f[x];
4     return x;
5 }

快速幂:

 1 int modexp(int a,int b,int n)   
 2 {   
 3     int ret=1;   
 4     int tmp=a;   
 5     while(b)   
 6     {
 7        if(b&0x1) ret=ret*tmp%n;   
 8        tmp=tmp*tmp%n;   
 9        b>>=1;   
10     }   
11     return ret;   
12 }   

欧几里得算法:

1 int gcd(int a,int b)
2 {
3     return b?gcd(b,a%b):a;
4 }

拓展欧几里德算法:

1 int gcd(int a,int b,int &x,int &y){
2     if (b==0){
3         x=1,y=0;
4         return a;
5     }
6     int q=gcd(b,a%b,y,x);
7     y-=a/b*x;
8     return q;
9 }

spfa:

 1 struct Edge
 2 {
 3     int to,w,next;
 4 }E[1000];
 5 int node=0,head[50];
 6 
 7 void insert(int u,int v,int w)
 8 {
 9     node++;
10     E[node]=Edge{v,w,head[u]};
11     head[u]=node;
12 }
13 
14 int spfa(int s,int t)
15 {
16     int dist[21];
17     bool vis[21];
18     memset(dist,0x7f,sizeof(dist));
19     memset(vis,0,sizeof(vis));
20     dist[s]=0;vis[s]=1;
21     queue<int> Q;
22     Q.push(s);
23     while(!Q.empty())
24     {
25         int q=Q.front();Q.pop();
26         for(int i=head[q];i;i=E[i].next)
27             if(dist[E[i].to]>dist[q]+E[i].w)
28             {
29                 dist[E[i].to]=dist[q]+E[i].w;
30                 if(!vis[E[i].to])
31                 {
32                     Q.push(E[i].to);
33                     vis[E[i].to]=1;
34                 }
35             }
36         vis[q]=0;
37     }
38     return dist[t];
39 }

 

spfa_dfs判负环:

 1 #include<iostream>
 2 #include<cstring>
 3 using namespace std;
 4 
 5 struct Edge
 6 {
 7     int to,w,next;
 8 }E[10000001];
 9 int node=0,head[10001],dist[10001];
10 bool vis[10001];
11 
12 int n,m;
13 bool flag;
14 
15 void insert(int u,int v,int w)
16 {
17     E[++node]=(Edge){v,w,head[u]};
18     head[u]=node;
19 }
20 
21 void spfa_dfs(int s)
22 {
23     vis[s]=1;
24     for(int i=head[s];i;i=E[i].next)
25     {
26         if(dist[E[i].to]>dist[s]+E[i].w)
27         {
28             if(vis[E[i].to]){flag=1;return;}
29             else
30             {
31                 dist[E[i].to]=dist[s]+E[i].w;
32                 spfa_dfs(E[i].to);
33             }
34         }
35     }
36     vis[s]=0;
37 }
38 
39 bool check()
40 {
41     flag=0;
42     memset(dist,0x7f,sizeof(dist));
43     memset(vis,0,sizeof(vis));
44     for(int i=1;i<=n;i++)
45     {
46         dist[i]=0;
47         spfa_dfs(i);
48         if(flag) return 1;
49     }
50     return 0;
51 }

 

floyd:

 1 const int maxn=105,
 2           INF=10000000;
 3 int n,Dist[maxn][maxn],Graph[maxn][maxn];
 4 int minn=INF;
 5 void floyd()
 6 {
 7     //memcpy(Graph,Dist,sizeof(Dist));
 8     for(int k=1;k<=n;k++)
 9     {/*拓展求最小环
10         for(int i=1;i<k;i++)
11             for(int j=i+1;j<k;j++)
12                 minn=min(minn,Dist[i][j]+Graph[j][k]+Graph[k][i]);*/
13         for(int i=1;i<=n;i++)
14             for(int j=1;j<=n;j++)
15             {
16                 int temp=Dist[i][k]+Dist[k][j];
17                 if(temp<Dist[i][j])
18                     Dist[i][j]=Dist[j][i]=temp;
19             }
20     }
21 }

 

Dijkstra:

 1 #include <iostream>
 2 #include <cstring>
 3 using namespace std;
 4 
 5 #define MAXN 10000000
 6 
 7 int n,e;
 8 int matrix[100][100];
 9 int dist[100];
10 
11 void Dijkstra(int s)
12 {
13     int u,minn;
14     bool vis[100];
15     memset(vis,0,sizeof(vis));
16     for(int i=0;i<n;i++)
17         if(matrix[s][i]>0)
18             dist[i]=matrix[s][i];
19         else dist[i]=MAXN;
20     vis[s]=1;dist[s]=0;
21     for(int i=1;i<n;i++)
22     {
23         minn=MAXN;
24         for(int j=0;j<n;j++)
25             if(!vis[j]&&dist[j]<minn)
26             {
27                 u=j;
28                 minn=dist[j];
29             }
30         vis[u]=1;
31         for(int j=0;j<n;j++)
32             if(!vis[j]&&matrix[u][j]>0&&minn+matrix[u][j]<dist[j])
33                 dist[j]=minn+matrix[u][j];
34     }
35 }
36 
37 int main()
38 {
39     int v;
40     cin>>n;
41     cin>>e;
42     memset(matrix,0,sizeof(matrix));
43     for(int i=0;i<e;i++)
44     {
45         int x,y,w;
46         cin>>x>>y>>w;
47         matrix[x][y]=w;
48     }
49     Dijkstra(0);
50     cin>>v;
51     cout<<dist[v];
52     return 0;
53 }

线段树:详见Codevs1082线段树练习3

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 using namespace std;
 5 
 6 struct node
 7 {
 8     int left,right,flag;
 9     long long sum;
10 }tree[600000];
11 
12 int n,q;
13 int a[200001];
14 
15 void build(int node,int left,int right)
16 {
17     tree[node].left=left;tree[node].right=right;
18     if(left==right)
19     {
20         tree[node].sum=a[left];
21         return;
22     }
23     int mid=(left+right)>>1;
24     build(node<<1,left,mid);
25     build(node<<1|1,mid+1,right);
26     tree[node].sum=tree[node<<1].sum+tree[node<<1|1].sum;
27 }
28 
29 void pushdown(int node)
30 {
31     int x=tree[node].right-tree[node].left+1;
32     tree[node<<1].flag+=tree[node].flag;
33     tree[node<<1|1].flag+=tree[node].flag;
34     tree[node<<1].sum+=(x-(x>>1))*tree[node].flag;
35     tree[node<<1|1].sum+=(x>>1)*tree[node].flag;
36     tree[node].flag=0;
37 }
38 
39 void update(int node,int left,int right,int x)
40 {
41     int mid=(tree[node].left+tree[node].right)>>1;
42     tree[node].sum+=(right-left+1)*x;
43     if(tree[node].left==left&&tree[node].right==right)
44     {
45         tree[node].flag+=x;
46         return;
47     }
48     if(tree[node].left==tree[node].right) return;
49     if(tree[node].flag>0) pushdown(node);
50     if(right<=mid) update(node<<1,left,right,x);
51     else if(left>mid) update(node<<1|1,left,right,x);
52     else
53     {
54         update(node<<1,left,mid,x);
55         update(node<<1|1,mid+1,right,x);
56     }
57     tree[node].sum=tree[node<<1].sum+tree[node<<1|1].sum;
58 }
59 
60 long long query(int node,int left,int right)
61 {
62     int mid=(tree[node].left+tree[node].right)>>1;
63     if(tree[node].left==left&&tree[node].right==right)
64         return tree[node].sum;
65     if(tree[node].flag>0) pushdown(node);
66     if(right<=mid)
67         return     query(node<<1,left,right);
68     else if(left>mid)
69         return query(node<<1|1,left,right);
70     else
71         return query(node<<1,left,mid)+query(node<<1|1,mid+1,right);
72 }

 

树状数组:

详见

Codevs1080 线段树练习

Codevs1081 线段树练习 2

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 using namespace std;
 5 
 6 int n,m;
 7 int f[100001];
 8 
 9 int lowbit(int x)
10 {
11     return x&(-x);
12 }
13 
14 void update(int x,int num)
15 {
16     while(x<=n)
17     {
18         f[x]+=num;
19         x+=lowbit(x);
20     }
21 }
22 
23 int sum(int x)
24 {
25     int sum=0;
26     while(x>0)
27     {
28         sum+=f[x];
29         x-=lowbit(x);
30     }
31     return sum;
32 }
33 
34 int main()
35 {
36     n=read();
37     for(int i=1;i<=n;i++)
38         update(i,read());
39     m=read();
40     for(int i=1;i<=m;i++)
41     {
42         int a=read(),x=read(),y=read();
43         if(a==1)update(x,y);
44         if(a==2)printf("%d
",sum(y)-sum(x-1));
45     }
46     return 0;
47 }

 

分块法:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<algorithm>
 5 using namespace std;
 6 
 7 int n,m,q,block;
 8 int a[1000001],b[1000001],pos[1000001],add[1000001];
 9 
10 void reset(int x)
11 {
12     int l=(x-1)*block+1,r=min(x*block,n);
13     for(int i=l;i<=r;i++)
14         b[i]=a[i];
15     sort(b+l,b+r+1);//对单个块内进行排序
16 }
17 
18 int find(int x,int z)//单个块内二分查找
19 {
20     int l=(x-1)*block+1,r=min(x*block,n);
21     int last=r;
22     while(l<=r)
23     {
24         int mid=(l+r)>>1;
25         if(b[mid]<z) l=mid+1;
26         else r=mid-1;
27     }
28     return last-l+1;
29 }
30 
31 void update(int x,int y,int z)
32 {
33     if(pos[x]==pos[y])//同个块则暴力修改
34         for(int i=x;i<=y;i++) a[i]=a[i]+z;
35     else//不同块修改左右两边的块
36     {
37         for(int i=x;i<=pos[x]*block;i++) a[i]=a[i]+z;
38         for(int i=(pos[y]-1)*block+1;i<=y;i++) a[i]=a[i]+z;
39     }
40     reset(pos[x]);reset(pos[y]);
41     for(int i=pos[x]+1;i<pos[y];i++)//其余块用add标记,表示增加了z
42         add[i]+=z;
43 }
44 
45 int query(int x,int y,int z)
46 {
47     int sum=0;
48     if(pos[x]==pos[y])//单个块暴力查找
49     {
50         for(int i=x;i<=y;i++)
51             if(a[i]+add[pos[i]]>=z) sum++;
52     }
53     else//多个块左右两边的块暴力查找
54     {
55         for(int i=x;i<=pos[x]*block;i++)
56             if(a[i]+add[pos[i]]>=z) sum++;
57         for(int i=(pos[y]-1)*block+1;i<=y;i++)
58             if(a[i]+add[pos[i]]>=z) sum++;
59     }
60     for(int i=pos[x]+1;i<pos[y];i++)//其余块每个二分查找
61         sum+=find(i,z-add[i]);
62     return sum;
63 }
64 
65 int main()
66 {
67     scanf("%d %d",&n,&q);
68     block=(int)sqrt(n);//每个块的大小
69     for(int i=1;i<=n;i++)
70     {
71         scanf("%d",&a[i]);
72         pos[i]=(i-1)/block+1;
73         b[i]=a[i];
74     }
75     if(n%block) m=n/block+1;//计算块的个数,如有多余则+1
76     else m=n/block;
77     for(int i=1;i<=m;i++) reset(i);//对每个块进行块内排序
78     for(int i=1;i<=q;i++)
79     {
80         char ch;int x,y,z;
81         scanf("
%c %d %d %d",&ch,&x,&y,&z);
82         if(ch=='M') update(x,y,z);
83         else printf("%d
",query(x,y,z));
84     }
85     return 0;
86 }

 

倍增算法:

RMQ:这里借鉴了一下黄学长的模板。。。Orz膜拜前辈

 1 #include<iostream>
 2 #include<cmath>
 3 #include<iostream>
 4 using namespace std;
 5 int A[200001];
 6 int MX[200001][18];
 7 int n,q;
 8 void RMP_INIT()
 9 {
10     for(int i=1;i<=n;i++)
11         MX[i][0]=A[i];
12     int m=log(n)/log(2);
13     for(int i=1;i<=m;i++)
14         for(int j=n;j>0;j--)
15         {
16              MX[j][i]=MX[j][i-1];
17             if(j+(1<<(i-1))<=n)MX[j][i]=max(MX[j][i],MX[j+(1<<(i-1))][i-1]); 
18         }
19  }
20 int RMP(int l,int r)
21 {
22     int m=log(r-l+1)/log(2);
23     return max(MX[l][m],MX[r-(1<<m)+1][m]);
24 }

 KMP算法:

 1 #include<iostream>
 2 #include<cstring>
 3 using namespace std;
 4 
 5 char S[255],T[255];
 6 int ls,lt;
 7 int next[255];
 8 
 9 void initnext(char *t,int *next)
10 {
11     int j=0;
12     int len=strlen(t);
13     memset(next,0,sizeof(next));
14     for(int i=1;i<len;i++)
15     {
16         while(j&&t[i]!=t[j]) j=next[j];
17         if(t[i]==t[j]) j++;
18         next[i+1]=j;
19     }
20 }
21 
22 int KMP(char *s,char *t)
23 {
24     int j=0,ans=0;
25     int ls=strlen(s),lt=strlen(t);
26     for(int i=0;i<ls;i++)
27     {
28         while(j&&s[i]!=t[j]) j=next[j];
29         if(s[i]==t[j]) j++;
30         if(j==lt)
31         {
32             ans++;
33             j=next[j];
34         }
35     }
36     return ans;
37 }

 

 

 高斯消元:感谢浙大学长。。。Orz

 1 #include<iostream>
 2 #include<cmath>
 3 using namespace std;
 4 
 5 #define eps 1e-9
 6 const int MAXN=220;
 7 double a[MAXN][MAXN],x[MAXN]; //方程的左边的矩阵和等式右边的值,求解之后 x存的就是结果  
 8 int equ,var;//方程数和未知数个数
 9  /* *返回0表示无解,1表示有解*/ 
10 int Gauss()
11 {
12     int i,j,k,col,max_r;
13     for(k=0,col=0;k<equ&&col<var;k++,col++)
14     {
15         max_r=k;
16         for(i=k+1;i<equ;i++)
17             if(fabs(a[i][col])>fabs(a[max_r][col])) max_r=i;
18         if(fabs(a[max_r][col])<eps) return 0;
19         if(k!=max_r)
20         {
21             for(j=col;j<var;j++) swap(a[k][j],a[max_r][j]);
22             swap(x[k],x[max_r]);
23         }
24         x[k]/=a[k][col];
25         for(j=col+1;j<var;j++) a[k][j]/=a[k][col];
26         a[k][col]=1;
27         for(i=0;i<equ;i++)
28             if(i!=k)
29             {
30                 x[i]-=x[k]*a[i][k];
31                 for(j=col+1;j<var;j++) a[i][j]-=a[k][j]*a[i][col];
32                 a[i][col]=0;
33             }
34     }
35     return 1;
36 }

分解质因数:感谢浙大学长。。。Orz

 1 long long fac[100],fac_num;
 2 void getfactor(int num)
 3 {
 4     fac_num=0; 
 5     for(int i=2;i*i<=num;i++)
 6     {
 7         if(num%i==0)
 8         {
 9              fac[fac_num++]=i;
10              while(num%i==0) num/=i; 
11          }
12      }
13      if(num>1) fac[fac_num++]=num;
14  }

欧拉函数:

 1 /*1.欧拉函数是积性函数,但不是完全积性函数,即φ(mn)=φ(n)*φ(m)只在(n,m)=1时成立. 
 2 2.对于一个正整数N的素数幂分解N=P1^q1*P2^q2*...*Pn^qn.
 3     φ(N)=N*(1-1/P1)*(1-1/P2)*...*(1-1/Pn).
 4 3.除了N=2,φ(N)都是偶数.
 5 4.设N为正整数,∑φ(d)=N (d|N).  求小于等于N的与N互质的数的和 :ans=N*phi(N)/2;*/
 6 /* 欧拉phi(x)函数等于不超过x且和x互素的整数个数。 */ 
 7 #include<iostream>
 8 #include<cstring>
 9 #include<algorithm>
10 using namespace std;
11 
12 const int MAXN=1000;
13 int phi[MAXN]; /* 单个欧拉函数值*/  
14 int euler_phi(int n)
15 {
16     int m=sqrt(n+0.5),ans=n;
17     for(int i=2;i<=m;i++)
18     {
19         if(n%i==0) ans=ans/i*(i-1);
20         while(n%i==0)n/=i;
21     }
22     if(n>1) ans=ans/n*(n-1);
23     return ans;
24 } 
25 /*欧拉函数 表*/  
26 void phi_table(int n)
27 {
28     memset(phi,0,sizeof(phi));
29     phi[1]=1;
30     for(int i=2;i<=n;i++)
31         if(!phi[i])
32             for(int j=i;j<=n;j+=i)
33             {
34                 if(!phi[j])phi[j]=j;
35                 phi[j]=phi[j]/i*(i-1);
36             }
37 }

埃氏筛法:O(nlog(logn))

 1 #include<iostream>
 2 #include<cstring>
 3 using namespace std;
 4 
 5 const int MAXN=1000;
 6 int isprime[MAXN];
 7 void getprime(int n)
 8 {
 9     memset(isprime,1,sizeof(isprime));
10     isprime[0]=isprime[1]=0;
11     for(int  i=0;i*i<n;i++)
12         if(isprime[i])
13             for(int j=i*i;j<=n;j+=i)
14                 isprime[j]=0;
15 }

欧拉筛法:

 1 const int MAXN=1000;
 2 int cnt=0;
 3 int prime[MAXN];
 4 bool mark[MAXN];
 5 void Prime(int x)
 6 {
 7     for(int i=2;i<=x;i++)
 8     {
 9         if(!mark[i]) prime[++cnt]=i;
10         for(int j=1;j<=cnt&&prime[j]*i<=x;j++)
11         {
12             mark[prime[j]*i]=1;
13             if(i%prime[j]==0) break;
14         }
15     }
16 }

后缀数组:

 1 #include<iostream>
 2 #include<cstring>
 3 using namespace std;
 4 
 5 const int MAXN=100000+5;
 6 int WA[MAXN],WB[MAXN],WV[MAXN],WS[MAXN];
 7 int Rank[MAXN],Height[MAXN];
 8  
 9 int cmp(int *r , int a, int b, int l)
10 {
11     return r[a] == r[b] && r[a+l] == r[b+l];
12 }
13 void DA(char *r , int *sa , int n, int m)
14 {
15     int i, j, p, *x = WA, *y = WB;
16     for(i = 0; i < m; i++)  WS[i] = 0;
17     for(i = 0; i < n; i++) WS[x[i] = r[i]]++;
18     for(i = 1; i < m; i++) WS[i] += WS[i-1];
19     for(i = n-1; i >= 0; i--) sa[--WS[x[i]]] = i;
20 
21     for(j = 1,p = 1; p < n ; j <<= 1,m = p)
22     {
23         for(p = 0, i = n - j; i < n; i++) y[p++]=i;
24         for(i = 0; i < n; i++)
25             if(sa[i] >= j)
26                 y[p++] = sa[i] - j;
27         for(i = 0; i < n; i++) WV[i] = x[y[i]];
28         for(i = 0; i < m; i++) WS[i] = 0;
29         for(i = 0; i < n; i++) WS[WV[i]]++;
30         for(i = 1; i < m; i++) WS[i] += WS[i-1];
31         for(i = n-1; i >= 0; i--) sa[--WS[WV[i]]] = y[i];
32         for(swap(x,y),p = 1,x[sa[0]] = 0,i = 1; i < n;i++)
33             x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
34     }
35 }
36 
37 void calheight(char *r,int *sa,int n)
38 {
39     int i,j,k=0;
40     for(i=1;i<=n;i++)Rank[sa[i]]=i;
41     for(i=0;i<n;Height[Rank[i++]]=k)
42         for(k?k--:0,j=sa[Rank[i]-1];r[i+k]==r[j+k];k++);
43     return;
44 }
45 
46 char str[MAXN];
47 int sa[MAXN];
48 
49 int main()
50 {
51     cin>>str;
52     int n=strlen(str);
53     str[n]=0;
54     DA(str,sa,n+1,128);
55     calheight(str,sa,n);
56 
57     return 0;
58 }

 

最大子串:

1 int maxSubstr() {
2     int sum = 0, answer = -INF;
3     for (int i = 1; i <= n; i++) {
4         sum += a[i];
5         answer = max(answer, sum);
6         sum = max(sum,0);
7     }
8     return answer;
9 }

 

 SG函数:(转自SimonS大佬征战亚洲赛时用的模板

 1 #define MAX 1005  
 2 /* 计算从1-n范围内的SG值。     
 3 Array(存储可以走的步数,Array[0]表示可以有多少种走法)     
 4 Array[]需要从小到大排序 */ 
 5 /*HDU1847博弈SG函数  
 6 1.可选步数为1-m的连续整数,直接取模即可,SG(x) = x % (m+1);  
 7 2.可选步数为任意步,SG(x) = x;  
 8 3.可选步数为一系列不连续的数,用GetSG(计算) */   
 9 
10 int SG[MAX], hash[MAX];  
11 void GetSG(int Array[], int n = MAX-1) 
12 {
13     memset(SG, 0, sizeof(SG));
14     for(int i = 0; i <= n; ++i)
15     {
16         memset(hash, 0, sizeof(hash));
17         for(int j = 1; j <= Array[0]; ++j) 
18         {
19             if(i < Array[j]) break;
20             hash[SG[i - Array[j]]] = 1;      
21         }
22         for(int j = 0; j <= n; ++j)
23             if(!hash[j]){ SG[i] = j;break; }
24     }
25 }

先占坑,慢慢填

原文地址:https://www.cnblogs.com/InWILL/p/5837452.html