ACM代码整合
[TOC]
如果发现文章中有不正确的地方,欢迎联系本人,感谢指出问题的每个人
PS:本文一切代码均有C/C++编写,参与JAVA组的人可以理解思想了以后尝试改写
!!!特别提醒
1、注意程序最后应有返回值,且返回值为0
2、万能头文件可以使用(bits/stdc++.h),比赛中使用c++的方法是,记得开全局空间using namespace std;
3、熟悉STL用法,包括vector、set、map、pair等结构的用法,这会给你剩下许多时间
4、例如max_element、lower_bound函数的用法请熟悉
5、在不能保证自己的算法的绝对正确性的情况下,可以选择保住现有的分,而不去尝试难度较高且自己没有把握的方法
1、最小公倍数gcd
int gcd(int a,int b){
	return b == 0 ? a : gcd(b,a%b);
} 
2、最大公约数lcm
int gcd(int a,int b){
	return b == 0 ? a : gcd(b,a%b);
} 
int lcm(int a,int b){
	return a*b/gcd(a,b);
}
3、Fibonacci数列
采用记忆化搜索的写法,或者使用状态转移的方法推导
- 记忆化搜索写法
 
int dp[1005];
int dfs(int n){
	if(n==1 || n==2){
		return 1;
	}
	if(dp[n] > 0){
		return dp[n];
	}else{
		dp[n] = dfs(n-1) + dfs(n-2);
		return dp[n];
	}	
}
- 状态转移写法
 
int dp[1000];
dp[1] = 1;
dp[2] = 1;
for(int i=3;i<1000;i++){
  dp[i] = dp[i-1] + dp[i-2];
} 
4、memset初始化
- memset在整形数组中推荐两种用法
 
int dp[1005];
memset(dp,0,sizeof(dp));//dp中的值全部置为了0
memset(dp,-1,sizeof(dp));//dp中的值全部置为了-1
有人问1,2,3其他的可行,当然是不行的,至于原因有兴趣想要知道的话,可以在网上了解
- memset在char数组中
    
char str[1005]; memset(str,0,sizeof(str));这样就是将char数组重置了,在多组输入的情况中,memset将会是一个非常高效的方法
 
5、fill初始化
int dp[100];
fill(dp,dp+10,5);
此时dp[0] -> dp[9]的值全部被置为了5
char str[100];
fill(str,str+10,'m');
此时str[0] -> str[9]的值全部被置为了m
以上两个例子相信大家一下子就对fill有所了解了吧,在实际运用中大家可以根据自己的需要使用fill和memset
6、ctype.h头文件
| 函数名称 | 函数原型 | 函数功能 | 函数返回 | 
|---|---|---|---|
| isalpha | int isalpha(char ch) | 检查ch是否是字母 | 是字母返回非0(在vs2015中为2),否则返回 0 | 
| iscntrl | int iscntrl(int ch) | 检查ch是否控制字符(其ASCII码在0和0x1F之间,数值为 0-31) | 是返回非0,否则返回 0 | 
| isdigit | int isdigit(char ch) | 检查ch是否是数字(0-9) | 是返回非0,否则返回0 | 
| isgraph | int isgraph(int ch) | 检查ch是否可显示字符(其ASCII码在0x21到0x7E之间),不包括空格 | 是返回非0,否则返回0 | 
| islower | int islower(int ch) | 检查ch是否小写字母(a-z) | 是返回非0,否则返回0 | 
| isupper | int isupper(int ch) | 检查ch是否是大写字母(A-Z) | 是返回非0,否则返回0 | 
| tolower | int tolower(int ch) | 将ch字符转换为小写字母 | 返回ch所代表的字符的小写字母 | 
| toupper | int toupper(int ch) | 将ch字符转换成大写字母 | 与ch相应的大写字母 | 
| isalnum | int isalnum(int ch) | 检查ch是否是字母或数字 | 是字母或数字返回非0,否则返回0 | 
| isprint | int isprint(int ch) | 检查ch是否是可打印字符(包括空格),其ASCII码在0x20到0x7E之间 | 是返回非0,否则返回0 | 
| ispunct | int ispunct(int ch) | 检查ch是否是标点字符(不包括空格),即除字母,数字和空格以外的所有可打印字符 | 是返回非0,否则返回0 | 
| isspace | int isspace(int ch) | 检查ch是否是空格符和跳格符(控制字符)或换行符 | 是返回非0,否则返回0 | 
| isxdigit | int isxdigit(int ch) | 检查ch是否是一个16进制数学字符(即0-9,或A-F,或a-f) | 是返回非0,否则返回0 | 
| isascii | int isascii(int ch) | 测试参数是否是ASCII码0-127 | 是返回非0,否则返回0 | 
7、素数系列
- 埃拉托斯特尼筛法,或者叫埃氏筛法
 
const int N = 100005;  
bool prime[N];  
void init(){  
    for(int i=2;i<N;i++) prime[i]=true;//先全部初始化为素数  
    for(int i=2;i*i<N;i++){  
        if(prime[i]){//如果i是质数  
            for(int j=i*i;j<N;j+=i){//从i的两倍开始的所有的倍数(i*i也行)  
                prime[j] = false;  
            }  
        }  
    }  
}  
- 预处理每个数的所有质因数
    
const int N = 100000 + 5; vector<int > prime_factor[N]; void init(){ for(int i = 2; i < N; i ++){ if(prime_factor[i].size() == 0){//如果i是质数 for(int j = i; j < N; j += i){ prime_factor[j].push_back(i); } } } } - 比如预处理每个数的所有因数
 
const int N = 100000 + 5;  
vector<int > factor[N];  
void init(){  
    for(int i = 2; i < N; i ++){  
        for(int j = i; j < N; j += i){  
            factor[j].push_back(i);  
        }  
    }  
}
- 预处理每个数的质因数分解
 
const int N = 100000 + 5;  
vector<int > prime_factor[N];  
void init(){  
    int temp;  
    for(int i = 2; i < N; i ++){  
        if(prime_factor[i].size() == 0){  
            for(int j = i; j < N; j += i){  
                temp = j;  
                while(temp % i == 0){  
                    prime_factor[j].push_back(i);  
                    temp /= i;  
                }  
            }  
        }  
    }  
}
http://blog.csdn.net/laichilizi/article/details/79390020
质因数分解题目↑(输入两个整数a、b,每行输出一个数的分解,形如k=a1a2a3…(a1<=a2<=a3….)
#include<bits/stdc++.h>    
using namespace std;    
const int N = 100000 + 5;    
vector<int > prime_factor[N];    
void init(){    
    int temp;    
    for(int i = 2; i < N; i ++){    
        if(prime_factor[i].size() == 0){    
            for(int j = i; j < N; j += i){    
                temp = j;    
                while(temp % i == 0){    
                    prime_factor[j].push_back(i);    
                    temp /= i;    
                }    
            }    
        }    
    }    
}    
int main()  
{    
    init();   
      
    int a,b;  
    scanf("%d %d",&a,&b);  
    vector<int>::iterator it;  
    for(int i=a;i<=b;i++){  
        cout<<i<<"=";  
        for(it = prime_factor[i].begin(); it != prime_factor[i].end(); it++){  
            if(it != prime_factor[i].end()-1) cout << *it <<"*";  
            else cout<<*it<<endl;  
        }  
              
    }   
}  
8、BFS系列
http://blog.csdn.net/laichilizi/article/details/75024841
- 马的移动↑,BFS入门题
 
http://blog.csdn.net/laichilizi/article/details/79383954
- 学霸的迷宫↑,BFS+记录操作方向
 
9、DFS系列
http://blog.csdn.net/laichilizi/article/details/79388913
- 
    
正则问题↑,一个由x() 组成的正则表达式。输入长度不超过100,保证合法,求这个正则表达式能接受的最长字符串的长度  
http://blog.csdn.net/laichilizi/article/details/78714582
- POJ-2386,简单区域连通问题,↑
 
10、动态规划(01背包,完全背包)
- 01背包(记忆化搜索)
 
#include<bits/stdc++.h>  
using namespace std;  
typedef long long ll;  
  
int n,W;  
int dp[105][10005];  
int w[105],v[105];  
  
int rec(int i,int j){  
    if(dp[i][j] >= 0){  
        return dp[i][j];  
    }  
    int res;  
    if(i == n){  
        res = 0;  
    }else if(j < w[i]){  
        res = rec(i + 1,j);  
    }else{  
        res = max(rec(i + 1,j),rec(i + 1,j - w[i])+v[i]);  
    }  
      
    return dp[i][j] = res;  
}  
  
int main()  
{  
    scanf("%d %d",&n,&W);  
      
    for(int i=0;i<n;i++){  
        scanf("%d %d",&w[i],&v[i]);   
    }  
      
    memset(dp,-1,sizeof(dp));  
      
    cout<<rec(0,W)<<endl;  
      
      
    return 0;  
}  
- 01背包(二维DP)
 
#include<bits/stdc++.h>  
using namespace std;  
typedef long long ll;  
  
int n,W;  
int dp[105][10005];  
int w[105],v[105];  
  
int main()  
{  
    scanf("%d %d",&n,&W);  
      
    for(int i=0;i<n;i++){  
        scanf("%d %d",&w[i],&v[i]);   
    }  
      
    memset(dp,0,sizeof(dp));  
      
    for(int i=n-1;i>=0;i--){  
        for(int j=0;j<=W;j++){  
            if(j < w[i]){  
                dp[i][j] = dp[i + 1][j];  
            }else{  
                dp[i][j] = max(dp[i+1][j],dp[i+1][j-w[i]]+v[i]);  
            }  
        }  
    }  
      
    cout<<dp[0][W]<<endl;  
      
    return 0;  
}  
- 01背包(一维最简化)
 
int dp[MAX_W +1];
void solve(){
    for(int i=0;i<n;i++){
        for(int j=W;j>=w[i];j--){
            dp[j] = max(dp[j],dp[j-w[i]]+v[i]);
        }
    }
    printf("%d\n",dp[W]);
}
- 完全背包(一维最简化)
 
int dp[MAX_W +1];
void solve(){
    for(int i=0;i<n;i++){
        for(int j=w[i];j<=W;j--){
            dp[j] = max(dp[j],dp[j-w[i]]+v[i]);
        }
    }
    printf("%d\n",dp[W]);
}
11、并查集
int par[MAX_N];
int rank[MAX_N];
//初始化n个元素 
void init(int n){
	for(int i=0;i<n;i++){
		par[i] = i;
		rank[i] = 0;
	}
}
//查询树的根 
int find(int x){
	if(par[x] == x){
		return x;
	}else{
		return par[x] = find(par[x]);
	}
}
//合并x和y所属的集合 
void unite(int x,int y){
	x = find(x);
	y = find(y);
	if(x == y) return;
	if(rank[x] < rank[y]){
		par[x] = y;
	}else{
		par[y] = x;
		if(rank[x] == rank[y]) rank[x]++;
	}
}
//判断x和y是否属于同一个集合
bool same(int x,int y){
	return find(x) == find(y);
}
经典例题:hdu1232
#include<cstdio>
using namespace std;
int par[1005];
int rank[1005];
//初始化n个元素
void init(int n){
	for(int i=1;i<=n;i++){
		par[i] = i;
		rank[i] = 0;
	}
}
//查询树的根
int find(int x){
	if(par[x] == x){
		return x;
	}else{
		return par[x] = find(par[x]);
	}
}
//合并x和y所属的集合
void unite(int x,int y){
	x = find(x);
	y = find(y);
	if(x == y) return;
	if(rank[x] < rank[y]){
		par[x] = y;
	}else{
		par[y] = x;
		if(rank[x] == rank[y]) rank[x]++;
	}
}
//判断x和y是否属于同一个集合
bool same(int x,int y){
	return find(x) == find(y);
}
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m)){
        if(n == 0) break;
        init(n);
        for(int i=0;i<m;i++){
            int x,y;
            scanf("%d%d",&x,&y);
            unite(x,y);
        }
        int ans = 0;
        for(int i=1;i<=n;i++){
            if(par[i] == i) ans ++;
        }
        printf("%d\n",ans-1);
    }
    return 0;
}
12、树状数组
int lowbit(int x){  
    return x&(-x);  
}  
void add(int x,int y){  
    while(x<=n){  
        c[x]+=y;  
        x+=lowbit(x);  
    }  
}  
//用于求序列中小于等于数字x的元素的个数
int sum(int x){  
    int ans=0;  
    while(x>0){  
        ans+=c[x];  
        x-=lowbit(x);  
    }       
    return ans;  
} 
http://blog.csdn.net/laichilizi/article/details/79450529
- 求逆序数↑
 
#include<iostream>  
#include<cstdio>  
using namespace std;  
int n;  
int aa[100005];  
int c[100005];  
int a[100005];  
int lowbit(int x)  
{  
    return x&(-x);  
}  
void add(int x,int y)  
{  
    while(x<=n)  
    {  
        c[x]+=y;  
        x+=lowbit(x);  
    }  
}  
int sum(int x)  
{  
    int ans=0;  
    while(x>0)  
    {  
        ans+=c[x];  
        x-=lowbit(x);  
    }  
       
    return ans;  
}  
   
int main()  
{  
    scanf("%d",&n);  
    for(int i=0;i<n;i++)  
    {  
        scanf("%d",&a[i]);  
    //  aa[a[i]]=a[i];  
    }   long long aans=0;  
    for(int i = 0 ; i<n;i++)  
    {  
        add(a[i],1);  
        aans+=i-sum(a[i]-1);  
    //  cout << i;  
    //  cout << sum(a[i]-1)<<endl;;  
    }  
   
    printf("%lld\n",aans);  
    return 0;  
} 
13、快速幂 and 矩阵快速幂
- 快速幂
 
typedef long long ll;
ll ksm(ll x,ll n,ll mod){
	ll res = 1;
	x = x % mod;
	while(x > 0){
		if(n & 1) res = res * x % mod;
		x = x * x % mod;
		n >>= 1;
	}
	return res;
}
- 矩阵快速幂
 
http://blog.csdn.net/wust_zzwh/article/details/52058209
#include<bits/stdc++.h>  
using namespace std;  
typedef long long ll;  
const int MOD=10000;  
struct mat  
{  
    ll a[2][2];  
};  
mat mat_mul(mat x,mat y)  
{  
    mat res;  
    memset(res.a,0,sizeof(res.a));  
    for(int i=0;i<2;i++)  
        for(int j=0;j<2;j++)  
        for(int k=0;k<2;k++)  
        res.a[i][j]=(res.a[i][j]+x.a[i][k]*y.a[k][j])%MOD;  
    return res;  
}  
void mat_pow(int n)  
{  
    mat c,res;  
    c.a[0][0]=c.a[0][1]=c.a[1][0]=1;  
    c.a[1][1]=0;  
    memset(res.a,0,sizeof(res.a));  
    for(int i=0;i<2;i++) res.a[i][i]=1;  
    while(n)  
    {  
        if(n&1) res=mat_mul(res,c);  
        c=mat_mul(c,c);  
        n=n>>1;  
    }  
    printf("%I64d\n",res.a[0][1]);  
}  
int main()  
{  
    int n;  
    while(~scanf("%d",&n)&&n!=-1)  
    {  
        mat_pow(n);  
    }  
    return 0;  
}
14、最短路
http://blog.csdn.net/acm_1361677193/article/details/48211319
15、string
http://blog.csdn.net/tengfei461807914/article/details/52203202
16、二分搜索
二分模型
while(l < r-1){
        int mid = r + (l - r)>> 1;
        if() l = mid;
        else r = mid;
    }
http://blog.csdn.net/laichilizi/article/details/79388555
- 分巧克力↑,经典二分题
 
17、字符串函数
- 字符处理函数:ctype.h
 
int isdigit(int ch)  ;//是否为数字,即ch是否是0-9中的字符
int isxdigit(int ch) ;//是否为十六进制数字,即ch是否是0-9  a-z A-Z 中的字符
int isalpha(int ch)  ;//是否为字母
int isalnum(int ch)  ;//是否为字母或数字
int islower(int ch)  ;//是否为小写字母
int isupper(int ch)  ;//是否为大写字母
int tolower(int ch)  ;//转换为小写字母
int toupper(int ch)  ;//转换为大写字母
- 字符串转换函数:stdlib.h
 
字符转换为数字:
double atof(char  *str) ; //将字符串str转换为double型数字
int    atoi (char  *str) ; //将字符串str转换为int 型数字
long   atol(char  *str) ; //将字符串str转换为long int 型数字
数字转换为字符:
//将int型数字digit按radix进制转换成字符串destStr
char * itoa (int digit, char *destStr, int radix) ;
//同理将long型数字转换成字符串
char * ltoa (long digit, char *destStr, int radix) ;
//同理将unsignedlong型数字转换成字符串
char * ultoa (long digit, char *destStr,int radix) ;
【以上库函数能够用于进制的转换】
类似函数还有:
double strtod(char *, char **) ;
long strtol(char *, char **, int) ;
unsigned long strtoul(char *, char **, int) ;
- 字符串操作函数:string.h
 
char * strcpy (char *s1, char *s2) ; //将字符串s2拷贝到数组s1中。
char * strncpy(char *s1,char *s2) ; //将字符串s2的最多n个字符拷贝到数组s1中
char * strcat (char *s1, char * s2) ; //将字符串s2连接在字符串s1尾部
char * strncat(char *s1, char *s2, size_tn) ; //将字符串s2中最多n个字符连接在s1之后
【注意:以上操作都要求目标字符数组有足够的存储空间】
- 符串比較函数:string.h
 
//比較字符串s1,s2.假设s1等于小于或大于s2。分别返回0。负值,正值
int strcmp(char *s1, char *s2 ) ;
int stricmp(char *s1, char *s2) ;//不区分大写和小写地比較两字符串
int strncmp(char *s1, char *s2, size_t n)  ;//比較两字符串的至多n个字符
- 字符串查找函数:string.h
 
//在字符串str中查找字符ch第一次出现的位置,假设找到了,就返回str中ch的指针,否则返回NULL
char *strchr(char*str, int ch) ;
//查找字符串str中字符ch的最后一次出现的位置(即:从后往前查找)
char*strrchr(char *str, int ch) ;
//查找字符串str1中第一次出现字符串str2的位置
char *strstr(char*str1, char *str2) ;
//查找字符串str2中随意字符在字符串str1中首次出现的位置。
char*strpbrk(char *str1, char *str2)
其他函数:
char *strrev(char * ) ; //字符串逆序函数
size_t strlen(char * str) ;//測字符串str的长度
注意:
strncpy( ) , strncat( ) , strncmp( ) ,这些函数仅仅能对两个不同的字符串操作,不能对同一字符串的不同部分操作。假设须要这么做,能够使用内存函数。
若把目标字符串初始置空,strncat()能够完毕非常多功能的操作。能够替代strncpy( )的功能,还能够提取子串等。
18、set & multiset
19、map & multimap
20、queue & priority_queue
- queue
 
queue入队,如例:q.push(x); 将x 接到队列的末端。
queue出队,如例:q.pop(); 弹出队列的第一个元素,注意,并不会返回被弹出元素的值。
访问queue队首元素,如例:q.front(),即最早被压入队列的元素。
访问queue队尾元素,如例:q.back(),即最后被压入队列的元素。
判断queue队列空,如例:q.empty(),当队列空时,返回true。
访问队列中的元素个数,如例:q.size()
- priority_queue
 
empty() 如果优先队列为空,则返回真
pop() 删除第一个元素
push() 加入一个元素
size() 返回优先队列中拥有的元素的个数
top() 返回优先队列中有最高优先级的元素
21、stack
empty() 堆栈为空则返回真
pop() 移除栈顶元素
push() 在栈顶增加元素
size() 返回栈中元素数目
top() 返回栈顶元素
22、vector
http://blog.csdn.net/duan19920101/article/details/50617190/
23、贪心算法
http://blog.csdn.net/qq_32400847/article/details/51336300
24、数制转换
http://blog.csdn.net/laichilizi/article/details/79381732
25、LCS
只计算LCS的数目
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
char a[1005],b[1005],ans[1005];
int dp[1005][1005];
int main()
{
	//freopen("input.txt","r",stdin);
	scanf("%s %s",a+1,b+1);
	int n = strlen(a+1);
	int m = strlen(b+1);
	memset(dp,0,sizeof(dp));
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(a[i] == b[j]){
				dp[i][j] = dp[i-1][j-1] + 1;
			}else{
				dp[i][j] = max(dp[i-1][j],dp[i][j-1]);
			}
		}
	}
	cout<<dp[n][m]<<endl;
	return 0;
}
除了LCS的数目,还输出对应的子串
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
char a[1005],b[1005],ans[1005];
int dp[1005][1005];
int main()
{
	//freopen("input.txt","r",stdin);
	scanf("%s %s",a+1,b+1);
	int n = strlen(a+1);
	int m = strlen(b+1);
	memset(dp,0,sizeof(dp));
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(a[i] == b[j]){
				dp[i][j] = dp[i-1][j-1] + 1;
			}else{
				dp[i][j] = max(dp[i-1][j],dp[i][j-1]);
			}
		}
	}
	int cur = 0;
	for(int i=n,j=m;dp[i][j];--i,--j){
		while(dp[i][j] == dp[i-1][j]) --i;
		while(dp[i][j] == dp[i][j-1]) --j;
		ans[cur++] = a[i];
	}
	reverse(ans,ans+cur);
	//ans[cur] = '\0';
	printf("%s\n",ans);
	return 0;
}
26、LIS
#include<bits/stdc++.h>  
using namespace std;  
#define INF 0x3f3f3f3f  
typedef long long ll;  
  
int dp[105];  
int a[105];  
  
int main()  
{  
    int n;  
    scanf("%d",&n);  
    for(int i=0;i<n;i++) scanf("%d",&a[i]);  
      
    int res = 0;  
    for(int i=0;i<n;i++){  
        dp[i] = 1;  
        for(int j=0;j<i;j++){  
            if(a[j] < a[i]){ //如果是包括相等,就改为<=   
                dp[i] = max(dp[i],dp[j]+1);  
            }  
        }  
        res = max(res,dp[i]);   
    }  
    cout<<res<<endl;  
  
    return 0;  
}
27、最大字段和
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll dp[50005];
ll solve(int n,ll *dp){
	ll ans = 0,b = 0;
	for(int i=0;i<n;i++){
		if(b>=0) b+=dp[i];
		else b = dp[i];
		if(b>ans) ans = b;
	}
	return ans;
}
int main(){
	//freopen("input.txt","r",stdin);
	int n;
	scanf("%d",&n);
	memset(dp,0,sizeof(dp));
	for(int i=0;i<n;i++) scanf("%lld",&dp[i]);
	ll p = solve(n,dp);
	cout<<p<<endl;
	return 0;
}
28、循环数组最大字段和
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll dp[50005];
ll solve(int n,ll *dp){
	ll ans = 0,b = 0;
	for(int i=0;i<n;i++){
		if(b>=0) b+=dp[i];
		else b = dp[i];
		if(b>ans) ans = b;
	}
	return ans;
}
int main(){
	freopen("input.txt","r",stdin);
	int n,sum = 0;
	scanf("%d",&n);
	memset(dp,0,sizeof(dp));
	for(int i=0;i<n;i++){
		scanf("%lld",&dp[i]);
		sum += dp[i];
	}
	ll ans1 = solve(n,dp);
	for(int i=0;i<n;i++) dp[i] = -dp[i];
	ll ans2 = solve(n,dp);
	ll ans = max(ans1,sum+ans2);
	cout<<ans<<endl;
	return 0;
}
29、最小正字段和
#include<iostream>  
#include<cstdio>  
#include<cstring>  
#include<algorithm>  
using namespace std;  
typedef long long LL;  
#define INF 0x3f3f3f3f;
struct node{  
    LL a;  
    int id_mi;  
    int id_ma;  
};  
bool operator <(node a,node b){  
    return a.a<b.a;  
}  
node dp[50010];  
int main(){  
    int n,a,i,j;  
    scanf("%d",&n);  
    LL ans=0;  
    dp[0].a=0;  
    dp[0].id_mi=0;  
    dp[0].id_ma=0;  
    for(i=1;i<=n;i++){  
        scanf("%lld",&dp[i].a);  
        dp[i].a+=dp[i-1].a;  
        dp[i].id_mi=i;  
        dp[i].id_ma=i;  
          
    }  
    sort(dp,dp+1+n);  
    j=0;  
    for(i=1;i<=n;i++)  
    {  
        if(dp[i].a==dp[j].a){  
            dp[j].id_mi=max(dp[j].id_mi,dp[i].id_mi);  
            dp[j].id_ma=min(dp[j].id_ma,dp[i].id_ma);  
        }  
        else dp[++j]=dp[i];  
    }  
    for(i=0;i<j;i++){  
        if(dp[i].id_mi<dp[i+1].id_ma&&dp[i+1].a-dp[i].a>0&&(ans==0||ans>dp[i+1].a-dp[i].a)){  
            ans=dp[i+1].a-dp[i].a;  
        }  
    }  
    cout<<ans<<endl;  
    return 0;  
}  
30、大数运算
http://blog.csdn.net/tt2767/article/details/45420067
31、Trie
const int MAX_N = 10000;  // Trie 树上的最大结点数
const int MAX_C = 26;  // 每个结点的子结点个数上限
struct Trie {
    int *ch[MAX_N];  // ch 保存了每个结点的 26 个可能的子结点编号,26 对应着 26 种小写字母,也就是说,插入的字符串全部由小写字母组成。初始全部为 -1
    int tot;  // 总结点个数(不含根结点),初始为 0
    int cnt[MAX_N];  // 以当前结点为终端结点的 Trie 树中的字符串个数
    void init() {  // 初始化 Trie 树,根结点编号始终为 0
        tot = 0;
        memset(cnt, 0, sizeof(cnt));
        memset(ch, 0, sizeof(ch));  // 将 ch 中的元素初始化为 NULL
    }
    void insert(char *str) {
        int p = 0;  // 从根结点(0)出发
        for (int i = 0; str[i]; ++i) {
            if (ch[p] == NULL) {
                ch[p] = new int[MAX_C];  // 只有 p 当包含子结点的时候才去开辟 ch[p] 的空间
                memset(ch[p], -1, sizeof(int) * MAX_C);  // 初始化为 -1
            }
            if (ch[p][str[i] - 'a'] == -1) {  // 该子结点不存在
                ch[p][str[i] - 'a'] = ++tot;  // 新增结点
            } 
            p = ch[p][str[i] - 'a'];  // 在 Trie 树上继续插入字符串 str
        }
        cnt[p]++;
    }
    int find(char *str) {  // 返回字符串 str 的出现次数
        int p = 0;
        for (int i = 0; str[i]; ++i) {
            if (ch[p][str[i] - 'a'] == -1) {
                return 0;
            }
            p = ch[p][str[i] - 'a'];
        }
        return cnt[p];
    }
};