东拼西凑的模板·持续更新中

一.常用算法

文中代码大量来自ACM算法模板 · 一些常用的算法模板-模板合集(稍加修改)

 

1.1 快速幂

 1 ll qpow(ll x, ll n , ll mod)
 2 {
 3     ll ans=1;
 4     while(n){
 5         if(n&1){
 6             ans=(ans*x)%mod;
 7             n--;
 8         }
 9         x=(x*x)%mod;
10         n>>=1;
11     }
12     return ans;
13 }
View Code

 

1.2 gcd

1 ll gcd(ll a,ll b){
2     return b==0?a:gcd(b,a%b);
3 }

 1.3 大数乘法

1 long long quick_multiply(long long a, long long b, long long mod) {
2     long long result = 0;
3     while (b) {
4         result = (result + (b % 2 * a) % mod) % mod;
5         a = a * 2 % mod;
6         b = b / 2;
7     }
8 }
快乘
 1 for(i=0; i<LA-1; i++)
 2     for(j=0; j<LB-1; j++)
 3         c[i+j]+=a[i]*b[j];
 4 
 5 for(i=0; i<LA+LB; i++)
 6     if(c[i]>=10)
 7     {
 8         c[i+1]+=c[i]/10;
 9         c[i]%=10;
10     }
核心代码
  1 //https://www.cnblogs.com/king-ding/p/bigIntegerMul.html
  2 #include<stdio.h>
  3 #include<string.h>
  4 #include<malloc.h>
  5 
  6 #define and &&           /**************/
  7 #define or ||            /* python风格 */
  8 #define not !            /*            */
  9 #define Int(X) (X - '0') /**************/
 10 
 11 int *multiBigInteger(const char *, const char *);
 12 int checkNum(const char *);
 13 
 14 int main(void)
 15 {
 16     char num1[100] = {'\0'}, num2[100] = {'\0'};
 17     printf("Please input two nunber(less than 100 digits):\n> ");
 18     while(scanf("%s%s", num1, num2) != EOF)
 19     {
 20         int *result = NULL;
 21         int i, change = 0;
 22         //对输入的数据进行检验
 23         if(strlen(num1) > 100 or strlen(num2) > 100)
 24         {
 25             printf("per number must less than 100 digits\n");
 26             return 1;
 27         }
 28 
 29         if(checkNum(num1) or checkNum(num2))
 30         {
 31             printf("ERROR: input must be an Integer\n");
 32             return 1;
 33         }
 34 
 35         printf("num1:\t%s\nnum2:\t%s\n", num1, num2);
 36 
 37         result = multiBigInteger(num1, num2);
 38 
 39         /* 输出结果result,result[0]保存着result的长度,
 40          * 所以下标要从1开始 */
 41         printf("result:\t");
 42         for(i = 1; i <= result[0]; i++)
 43         {
 44             if(result[i] != 0) //这一步用来去掉前导0,第一位为0跳过不输出
 45                 change = 1;
 46             if(not change)
 47             {
 48                 if(i > 1)        //这一步用来判断结果是否为0,
 49                     {                //如果结果第二位还是0,就判断为0
 50                         printf("0");
 51                         break;
 52                     }
 53                 continue;
 54             }
 55             printf("%d", result[i]);
 56         }
 57         printf("\n");
 58         printf("\nPlease input two nunber(less than 100 digits):\n> ");
 59     }
 60     return 0;
 61 } 
 62 
 63 //用于检测输入的是否是数字,如果是就返回0,不是就返回1
 64 int checkNum(const char *num)
 65 {
 66     int i;
 67     for(i = 0; (size_t)i < strlen(num); i++)
 68     {
 69         if(num[i] < '0' or num[i] > '9')
 70         {
 71             return 1;
 72         }
 73     }
 74     return 0;
 75 }
 76 
 77 //返回结果result,为一片内存块,类似数组
 78 int *multiBigInteger(const char *num1, const char *num2)
 79 {
 80     int *result = NULL;                //用来保存最终结果
 81     int num1Len = strlen(num1);        //num1的长度
 82     int num2Len = strlen(num2);        //num2的长度
 83     int resultLen;                     //结果的最大长度
 84     int i, j;                          //循环计数器
 85     resultLen = num1Len + num2Len;     //结果长度最大为num1长度和num2长度之和
 86     //初始化result为0
 87     result = (int *)malloc((resultLen+1)*sizeof(int));
 88     memset(result, 0, (resultLen+1)*sizeof(int));
 89 
 90     result[0] = resultLen; //result的第一位是用来保存result的长度的。
 91     /* num1乘以num2,由于这里采用先不进位的算法,所以算法是按从左到右
 92      * 按顺序来乘,然后将每位的结果保存到result的每一位中,循环一次
 93      * reult就从下一位开始求和。如下:(左边为正常算法,右边为本程序算法)
 94      *
 95      *     54321     |     54321
 96      *    ×  123     |    ×  123
 97      *    -------    |   --------
 98      *    162963     |     54321
 99      *   108642      |     108642
100      *   54321       |      162963
101      *   --------    |   ---------
102      *   6681483     |     6681483
103      *
104      * */
105     for(j = 0; j < num2Len; j++)
106     {
107         for(i = 0; i < num1Len; i++)
108         {
109             /* result第一位是用来保存result长度的,而第二位是保存结果最后的进位的
110              * 没有进位,则result[1]为0,所以每位相乘之和是从第三位(即result[2])
111              * 开始。这里是本程序的比较巧妙的地方,需要仔细想想。
112              * */
113             result[i+j+2] += Int(num1[i]) * Int(num2[j]);
114         }
115     }
116 
117     /* 这个循环用来处理进位的,所以要从result的最后一位一直处理到首位。
118      * 要注意result的总长度是resultLen+1,有一位是保存result的长度,而
119      * C语言下标是从0开始,所以result的最后一位的下标就是resultLen,而
120      * 第一位就是1。*/
121     for(i = resultLen; i > 1; i--)
122     {
123         result[i-1] += result[i]/10;
124         result[i] = result[i]%10;
125     }
126     printf("num1Len:%d\nnum2Len:%d\n", num1Len, num2Len);
127     return result;
128 }
129 
130 大整数相乘2完整代码
完整代码
 1 //JAVA 大数相乘 
 2 import java.math.BigInteger;
 3 import java.util.*;
 4 import java.io.*;
 5 
 6 public class Main
 7 {
 8     public static void main(String args[])
 9     {
10         Scanner cin = new Scanner(System.in);
11             BigInteger a = cin.nextBigInteger();
12             BigInteger b = cin.nextBigInteger();
13             BigInteger ans = a.multiply(b);
14             System.out.println(ans);
15     }
16 }
JAVA

1.4高精度幂运算

 1 //JAVA 高精度幂 
 2 import java.io.*;
 3 import java.math.BigDecimal;
 4 import java.util.*;
 5 
 6 public class Main
 7 {
 8     public static void main(String args[])
 9     {
10         Scanner cin = new Scanner(System.in);    
11         while(cin.hasNext())
12         {
13             BigDecimal ans = cin.nextBigDecimal();
14             int n = cin.nextInt();
15             String res = ans.pow(n).stripTrailingZeros().toPlainString(); //整数去掉后面的0和小数点 
16             if(res.startsWith("0")) //去掉前导0 
17             {
18                 res = res.substring(1);
19             }
20             System.out.println(res);
21         }
22     }
23 }
View Code

 更多java大数使用见:https://blog.csdn.net/morejarphone/article/details/51884888

1.6 二分查找

1 int l=0,r=n;
2     while(l+1<r){
3         int k=l+r>>1;
4         if(check(k))l=k;
5         else r=k;
6     }

1.7 矩阵快速幂

 1 struct Matrix {
 2     ll mat[3][3];
 3 };
 4 
 5 Matrix mul(Matrix a, Matrix b) {
 6     Matrix ret;
 7     for (int i = 0; i < 3; i++)
 8         for (int j = 0; j < 3; j++) {
 9             ret.mat[i][j] = 0;
10             for (int k = 0; k < 3; k++) {
11 //                if(ret.mat[i][k]&&ret.mat[k][j])
12                     ret.mat[i][j] = (ret.mat[i][j] + a.mat[i][k] * b.mat[k][j] % mod) % mod;
13             }
14         }
15     return ret;
16 }
17 
18 Matrix qpow(Matrix a, ll n) {
19     Matrix ret;
20     memset(ret.mat, 0, sizeof(ret.mat));
21     ret.mat[0][0] = ret.mat[1][1] = ret.mat[2][2] = 1;
22     Matrix tmp = a;
23     while (n) {
24         if (n & 1)ret = mul(ret, tmp);
25         tmp = mul(tmp, tmp);
26         n >>= 1;
27     }
28     return ret;
29 }
kuangbin

 

 1 //https://blog.csdn.net/wust_zzwh/article/details/52058209
 2 const int N=10;
 3 int tmp[N][N];
 4 void multi(int a[][N],int b[][N],int n)
 5 {
 6     memset(tmp,0,sizeof tmp);
 7     for(int i=0;i<n;i++)
 8         for(int j=0;j<n;j++)
 9         for(int k=0;k<n;k++)
10         tmp[i][j]+=a[i][k]*b[k][j];
11     for(int i=0;i<n;i++)
12         for(int j=0;j<n;j++)
13         a[i][j]=tmp[i][j];
14 }
15 int res[N][N];
16 void Pow(int a[][N],int n)
17 {
18     memset(res,0,sizeof res);//n是幂,N是矩阵大小
19     for(int i=0;i<N;i++) res[i][i]=1;
20     while(n)
21     {
22         if(n&1)
23             multi(res,a,N);//res=res*a;复制直接在multi里面实现了;
24         multi(a,a,N);//a=a*a
25         n>>=1;
26     }
27 }
View Code
#include"bits/stdc++.h"
#define vec vector<long long>
#define Mt  vector<vec>
using namespace std;
const int mod = 1e9 + 7;
int n;

Mt mul(Mt &A,Mt &B){
    Mt C(A.size(),vec(B[0].size()));
    for(int i=0;i<A.size();i++)
        for(int j=0;j<B[0].size();j++)
        for(int k=0;k<B.size();k++)
        C[i][j]=(C[i][j]+A[i][k]*B[k][j])%mod;
    return C;
}

long long qpow(long long x,long long n)
{
    long long ans=1;
    while(n){
        if(n&1){
            ans=(ans*x)%mod;
        }
        n>>=1;
        x=(x*x)%mod;
    }
    return ans;
}


Mt qpow(Mt A,long long n){
    Mt B(A.size(),vec(A.size()));
    for(int i=0;i<A.size();i++)
        B[i][i]=1;
    for(;n;n>>=1){if(n&1)B=mul(B,A);A=mul(A,A);}
    return B;
}

int main(){
    while(cin>>n){
        Mt X(4,vec(4));Mt Y(1,vec(4));Mt A(1,vec(5));Mt C(1,vec(5));
        X[0][0]=1; X[0][1]=1;X[1][2]=1;X[2][0]=1; X[2][3]=1;X[3][0]=1;
        Y[0][0]=6;Y[0][1]=4;Y[0][2]=2;Y[0][3]=1;
        A[0][0]=17,A[0][1]=7,A[0][2]=2,A[0][3]=0;A[0][4]=0;
        if(n<=5){
            printf("%lld\n",A[0][5-n]);
        }
        else{
            X=qpow(X,n-3);
            C=mul(Y,X);
            printf("%lld\n",(qpow(2,n)-C[0][0]+mod)%mod );
        }
    }
    return 0;
}
常用

 1.8逆序数(归并排序)

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #define ll long long
 6 using namespace std;
 7 const int N=1e6+5;
 8 int f[N],t[N];
 9 ll ans;
10 void Merge(int l,int m,int r) //左右两个表合并成一个表
11 {
12     int i=l,j=m+1,cnt=0;
13     while(i<=m && j<=r)
14     {
15         if(f[i]<=f[j])
16             t[cnt++]=f[i++];
17         else
18         {
19             ans+=m-i+1;
20             t[cnt++]=f[j++]; //核心代码,求解逆序数个数。
21         }
22     }
23     while(i<=m) //若左表不空
24         t[cnt++]=f[i++];
25     while(j<=r) //若右表不空
26         t[cnt++]=f[j++];
27     for(int k=0;k<cnt;) //修改原数组
28         f[l++]=t[k++];
29 }
30 void Merge_sort(int l,int r) //归并排序
31 {
32     if(l==r)
33         return ;
34     else
35     {
36         int m=(l+r)>>1;
37         Merge_sort(l,m);
38         Merge_sort(m+1,r);
39         Merge(l,m,r);
40     }
41 }
42 int  main()
43 {
44     int n;
45     ll x,y;
46     while(scanf("%d%lld%lld",&n,&x,&y)==3)
47     {
48         for(int i=0;i<n;i++) scanf("%d",&f[i]);
49         ans=0;
50         Merge_sort(0,n-1);
51         printf("%lld\n",min<ll>(x,y)*ans);
52     }
53     return 0;
54 }
View Code

 1.9 全排列遍历

 1 STL的全排列支持可重集
 2 int n;
 3 int p[maxn];
 4 void solve()
 5 {
 6     scanf("%d",&n);
 7     for(int i = 0;i<n;i++)
 8     {
 9         scanf("%d",&p[i]);
10     }
11     do
12     {
13         for(int i = 0;i<n;i++) printf("%d ",p[i]);
14         printf("\n");
15 
16     }while(next_permutation(p,p+n));
17 }
View Code

 1.10 lowbit(二进制最低位)

int lowbit(int x){    return x&(-x);    }

 1.11 组合数打表预处理

 1 void init()
 2 {
 3     Q[0]=1,Q[1]=2;
 4     C[1][0] = C[1][1] = 1;
 5     for (int i = 2; i < 110; i++)
 6     {
 7         Q[i] = Q[i-1]*2;
 8         C[i][0] = 1;
 9         for (int j = 1; j < 110; j++)
10             C[i][j] = C[i - 1][j] + C[i - 1][j - 1];
11     }
12 }
View Code

 1.12 求逆元

 1 lint ex_gcd(lint a,lint b,lint &x,lint &y)//扩展欧几里得(扩展gcd)
 2 {
 3     if (a==0&&b==0) return -1;
 4     if (b==0){x=1;y=0;return a;}
 5     lint d=ex_gcd(b,a%b,y,x);
 6     y-=a/b*x;
 7     return d;
 8 }
 9  
10 lint mod_inverse(lint a,lint n)//乘法逆元
11 {
12     lint x,y;
13     lint d = ex_gcd(a,n,x,y);
14     return (x%n+n)%n;
15 }
View Code
 1 int find(int x)  
 2 {  
 3     int k=mod-2,ans=1;  
 4     while(k)  
 5     {  
 6         if (k&1) ans=(lint)ans*x%mod;  
 7         x=(lint)x*x%mod;  
 8         k>>=1;  
 9     }  
10     return ans;  
11 }  x在%mod下的逆元
View Code

 

 

二.素数

2.1 素数筛

 1 const int MAX = 100;
 2 //快速素数筛,只筛选小于等于素数i的素数与i的乘积,既不会造成重复筛选,又不会遗漏。时间复杂度几乎是线性的。
 3 //模板来源https://blog.csdn.net/stack_queue/article/details/53560887
 4 long long su[MAX],cnt;
 5 bool isprime[MAX];
 6 void prime()
 7 {
 8     cnt=1;
 9     memset(isprime,1,sizeof(isprime));//初始化认为所有数都为素数
10     isprime[0]=isprime[1]=0;//0和1不是素数
11     for(long long i=2;i<=MAX;i++)
12     {
13         if(isprime[i])
14             su[cnt++]=i;//保存素数i
15         for(long long j=1;j<cnt&&su[j]*i<MAX;j++)
16         {
17             isprime[su[j]*i]=0;//筛掉小于等于i的素数和i的积构成的合数
18         }
19     }
20 }
21 int main()
22 {
23     prime();
24     for(long long i=1;i<cnt;i++)
25         printf("%d  ",su[i]);
26     return 0;
27 }
View Code

2.2 米勒罗宾素数测试

 1 //https://blog.csdn.net/u013654696/article/details/40056179
 2 // 18位素数:154590409516822759
 3 // 19位素数:2305843009213693951 (梅森素数)
 4 // 19位素数:4384957924686954497
 5 LL prime[6] = {2, 3, 5, 233, 331};
 6 LL qmul(LL x, LL y, LL mod) { // 乘法防止溢出, 如果p * p不爆LL的话可以直接乘; O(1)乘法或者转化成二进制加法
 7 
 8 
 9     return (x * y - (long long)(x / (long double)mod * y + 1e-3) *mod + mod) % mod;
10     /*
11     LL ret = 0;
12     while(y) {
13         if(y & 1)
14             ret = (ret + x) % mod;
15         x = x * 2 % mod;
16         y >>= 1;
17     }
18     return ret;
19     */
20 }
21 LL qpow(LL a, LL n, LL mod) {
22     LL ret = 1;
23     while(n) {
24         if(n & 1) ret = qmul(ret, a, mod);
25         a = qmul(a, a, mod);
26         n >>= 1;
27     }
28     return ret;
29 }
30 bool Miller_Rabin(LL p) {
31     if(p < 2) return 0;
32     if(p != 2 && p % 2 == 0) return 0;
33     LL s = p - 1;
34     while(! (s & 1)) s >>= 1;
35     for(int i = 0; i < 5; ++i) {
36         if(p == prime[i]) return 1;
37         LL t = s, m = qpow(prime[i], s, p);
38         while(t != p - 1 && m != 1 && m != p - 1) {
39             m = qmul(m, m, p);
40             t <<= 1;
41         }
42         if(m != p - 1 && !(t & 1)) return 0;
43     }
44     return 1;
45 }
View Code

 2.3 分解质因数

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<stdlib.h>
  4 #include<time.h>
  5 #include<iostream>
  6 #include<algorithm>
  7 #include <map>
  8 using namespace std;
  9 
 10 map<int,int> mp;
 11 map<int,int>::iterator it;
 12 //****************************************************************
 13 // Miller_Rabin 算法进行素数测试
 14 //速度快,而且可以判断 <2^63的数
 15 //****************************************************************
 16 const int S=100;//随机算法判定次数,S越大,判错概率越小
 17 
 18 
 19 //计算 (a*b)%c.   a,b都是long long的数,直接相乘可能溢出的
 20 //  a,b,c <2^63
 21 long long mult_mod(long long a,long long b,long long c)
 22 {
 23     a%=c;
 24     b%=c;
 25     long long ret=0;
 26     while(b)
 27     {
 28         if(b&1){ret+=a;ret%=c;}
 29         a<<=1;
 30         if(a>=c)a%=c;
 31         b>>=1;
 32     }
 33     return ret;
 34 }
 35 
 36 
 37 
 38 //计算  x^n %c
 39 long long pow_mod(long long x,long long n,long long mod)//x^n%c
 40 {
 41     if(n==1)return x%mod;
 42     x%=mod;
 43     long long tmp=x;
 44     long long ret=1;
 45     while(n)
 46     {
 47         if(n&1) ret=mult_mod(ret,tmp,mod);
 48         tmp=mult_mod(tmp,tmp,mod);
 49         n>>=1;
 50     }
 51     return ret;
 52 }
 53 
 54 
 55 
 56 
 57 
 58 //以a为基,n-1=x*2^t      a^(n-1)=1(mod n)  验证n是不是合数
 59 //一定是合数返回true,不一定返回false
 60 bool check(long long a,long long n,long long x,long long t)
 61 {
 62     long long ret=pow_mod(a,x,n);
 63     long long last=ret;
 64     for(int i=1;i<=t;i++)
 65     {
 66         ret=mult_mod(ret,ret,n);
 67         if(ret==1&&last!=1&&last!=n-1) return true;//合数
 68         last=ret;
 69     }
 70     if(ret!=1) return true;
 71     return false;
 72 }
 73 
 74 // Miller_Rabin()算法素数判定
 75 //是素数返回true.(可能是伪素数,但概率极小)
 76 //合数返回false;
 77 
 78 bool Miller_Rabin(long long n)
 79 {
 80     if(n<2)return false;
 81     if(n==2)return true;
 82     if((n&1)==0) return false;//偶数
 83     long long x=n-1;
 84     long long t=0;
 85     while((x&1)==0){x>>=1;t++;}
 86     for(int i=0;i<S;i++)
 87     {
 88         long long a=rand()%(n-1)+1;//rand()需要stdlib.h头文件
 89         if(check(a,n,x,t))
 90             return false;//合数
 91     }
 92     return true;
 93 }
 94 
 95 
 96 //************************************************
 97 //pollard_rho 算法进行质因数分解
 98 //************************************************
 99 long long factor[10000];//质因数分解结果(刚返回时是无序的)
100 int tol;//质因数的个数。数组小标从0开始
101 
102 long long gcd(long long a,long long b)
103 {
104     if(a==0)return 1;//???????
105     if(a<0) return gcd(-a,b);
106     while(b)
107     {
108         long long t=a%b;
109         a=b;
110         b=t;
111     }
112     return a;
113 }
114 
115 long long Pollard_rho(long long x,long long c)
116 {
117     long long i=1,k=2;
118     long long x0=rand()%x;
119     long long y=x0;
120     while(1)
121     {
122         i++;
123         x0=(mult_mod(x0,x0,x)+c)%x;
124         long long d=gcd(y-x0,x);
125         if(d!=1&&d!=x) return d;
126         if(y==x0) return x;
127         if(i==k){y=x0;k+=k;}
128     }
129 }
130 //对n进行素因子分解
131 void findfac(long long n)
132 {
133     if(Miller_Rabin(n))//素数
134     {
135         mp[n]++;
136         return;
137     }
138     long long p=n;
139     while(p>=n)p=Pollard_rho(p,rand()%(n-1)+1);
140     findfac(p);
141     findfac(n/p);
142 }
143 
144 int main()
145 {
146     srand(time(NULL));
147     long long n;
148     while(scanf("%lld",&n)!=EOF)
149     {
150         if(n==1)
151         {
152             printf("1\n");
153             continue;
154         }
155         mp.clear();
156         tol=0;
157         findfac(n);
158         long long sum=1;
159         for(it=mp.begin();it!=mp.end();it++){
160             sum*=(1+it->second);
161         }
162         printf("%lld\n",sum);
163     }
164     return 0;
165 }
View Code

 

三.数学相关

3.1 扩展欧几里得算法

 1 int exgcd(int a,int b,int &x,int &y)
 2 {
 3     if(b==0)
 4     {
 5         x=1;
 6         y=0;
 7         return a;
 8     }
 9     int r=exgcd(b,a%b,x,y);
10     int t=x;
11     x=y;
12     y=t-a/b*y;
13     return r;
14 }
View Code

 3.2 向量基本计算方法

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cctype>
 4 #include<cmath>
 5 #include<algorithm>
 6 #define eps 1e-8
 7 using namespace std;
 8 
 9 struct Point
10 {
11     double x,y;
12     Point(){}
13     Point(double x,double y):x(x),y(y){}
14     double operator *(const Point B)const{ return x*B.y-y*B.x; }
15     Point operator -(const Point B)const{ return Point(x-B.x,y-B.y); }
16     Point operator +(const Point B)const{ return Point(x+B.x,y+B.y); }
17     Point operator *(const double B)const{ return Point(x*B,y*B); }
18 }A,B,C,D,L1,L2,P,Q,MA,MC;
19 
20 int main()
21 {
22     int T;scanf("%d",&T);
23     for(;T--;)
24     {
25         scanf("%lf%lf%lf%lf%lf%lf%lf%lf",&A.x,&A.y,&B.x,&B.y,&C.x,&C.y,&D.x,&D.y);
26         if(A.y==B.y || C.y==D.y){ printf("0.00\n");continue; }
27         if(A.y<B.y) swap(A,B);
28         if(C.y<D.y) swap(C,D);
29         double a=(C-A) * (D-A),b = (D-B) * (C-B);
30         if(a*b<-eps){ printf("0.00\n"); continue;}
31         P=(B-A) * (a / (a+b)) + A;
32         if(P.y>C.y || P.y<D.y){ printf("0.00\n");continue; }
33         if(A.y>C.y)
34         {
35             Q=B + (A-B) * ((C.x-B.x)/(A.x-B.x));
36             if(Q.y>=C.y && A.y>=Q.y){ printf("0.00\n");continue;}
37             MA=B + (A-B) * ((C.y-B.y)/(A.y-B.y));
38             printf("%.2lf\n",fabs((MA-P) * (C-P) / 2));
39         }
40         else 
41         {
42             Q=D + (C-D) * ((A.x-D.x)/(C.x-D.x));
43             if(Q.y>=A.y && C.y>=Q.y){ printf("0.00\n");continue; }
44             MC=D+(C-D) * ((A.y-D.y) / (C.y-D.y));
45             printf("%.2lf\n",fabs((MC-P) * (A-P) / 2) );
46         }
47     }
48 }
View Code
 1 //https://blog.csdn.net/qq_16657927/article/details/79942140
 2 /* 
 3     |16/11/06ztx| 
 4 */  
 5   
 6 struct node {    
 7     double x; // 横坐标    
 8     double y; // 纵坐标    
 9 };    
10   
11 typedef node Vector;  
12   
13 Vector operator + (Vector A, Vector B) { return Vector(A.x + B.x, A.y + B.y); }    
14 Vector operator - (Point A, Point B) { return Vector(A.x - B.y, A.y - B.y); }    
15 Vector operator * (Vector A, double p) { return Vector(A.x*p, A.y*p); }    
16 Vector operator / (Vector A, double p) { return Vector(A.x / p, A.y*p); }    
17   
18 double Dot(Vector A, Vector B) { return A.x*B.x + A.y*B.y; } // 向量点乘    
19 double Length(Vector A) { return sqrt(Dot(A, A)); }  // 向量模长    
20 double Angle(Vector A, Vector B) { return acos(Dot(A, B) / Length(A) / Length(B)); }  // 向量之间夹角    
21   
22 double Cross(Vector A, Vector B) { // 叉积计算 公式    
23     return A.x*B.y - A.y*B.x;    
24 }    
25   
26 Vector Rotate(Vector A, double rad) // 向量旋转 公式  {    
27     return Vector(A.x*cos(rad) - A.y*sin(rad), A.x*sin(rad) + A.y*cos(rad));    
28 }    
29   
30 Point getLineIntersection(Point P, Vector v, Point Q, Vector w) { // 两直线交点t1 t2计算公式     
31     Vector u = P - Q;     
32     double t = Cross(w, u) / Cross(v, w);  // 求得是横坐标    
33     return P + v*t;  // 返回一个点    
34 }    
View Code

3.3 求多边形面积

 1 /* 
 2     |16/11/06ztx| 
 3 */  
 4   
 5 node G[maxn];    
 6 int n;    
 7   
 8 double Cross(node a, node b) { // 叉积计算    
 9     return a.x*b.y - a.y*b.x;    
10 }    
11   
12   
13 int main()    
14 {    
15     while (scanf("%d", &n) != EOF && n) {    
16         for (int i = 0; i < n; i++)     
17             scanf("%lf %lf", &G[i].x, &G[i].y);    
18         double sum = 0;    
19         G[n].x = G[0].x;    
20         G[n].y = G[0].y;    
21         for (int i = 0; i < n; i++) {     
22                 sum += Cross(G[i], G[i + 1]);    
23         }    
24         // 或者    
25             //for (int i = 0; i < n; i++) {    
26                 //sum += fun(G[i], G[(i + 1)% n]);    
27             //}    
28         sum = sum / 2.0;    
29         printf("%.1f\n", sum);    
30     }    
31     system("pause");    
32     return 0;    
33 }  
View Code

3.4 判断直线相交

 1 /*
 2     |16/11/06ztx|
 3 */
 4 
 5 node P[35][105];     
 6 
 7 double Cross_Prouct(node A,node B,node C) {     //  计算BA叉乘CA     
 8     return (B.x-A.x)*(C.y-A.y)-(B.y-A.y)*(C.x-A.x);      
 9 }      
10 bool Intersect(node A,node B,node C,node D)  {  //  通过叉乘判断线段是否相交;           
11     if(min(A.x,B.x)<=max(C.x,D.x)&&         //  快速排斥实验;      
12        min(C.x,D.x)<=max(A.x,B.x)&&      
13        min(A.y,B.y)<=max(C.y,D.y)&&      
14        min(C.y,D.y)<=max(A.y,B.y)&&      
15        Cross_Prouct(A,B,C)*Cross_Prouct(A,B,D)<0&&      //  跨立实验;      
16        Cross_Prouct(C,D,A)*Cross_Prouct(C,D,B)<0)       //  叉乘异号表示在两侧;      
17        return true;      
18     else return false;      
19 }    
View Code

 3.5 凸包

  1 /*
  2 向量叉积判断多边形凹凸
  3 
  4        对于连续的三个点p0,p1,p2,另向量a=p1-p0,b=p2-p1若是凸多边形,那么b相对于a一定是向逆时针方向
  5 
  6 旋转的。
  7 
  8  判断两向量的旋转方向,可以使用向量的叉积 a×b = x1×y2 - x2×y1
  9 
 10   a×b > 0 b在a的逆时针方向
 11   a×b = 0 b平行于a(共线)
 12   a×b < 0 b在a的顺时针方向
 13 
 14 要注意的是,对于最后一个点pn,还要和起始的两个点p0,p1判断一次。
 15 */
 16  
 17 
 18 #include <cstdio>
 19 #include <cmath>
 20 #include <cstdlib>
 21 #include <algorithm>
 22 #define eps 1e-8
 23 #define MAXN 110
 24 using namespace std;
 25 struct Point
 26 {
 27     double x, y;
 28     Point(){}
 29     Point(double X, double Y){
 30         x = X; y = Y;
 31     }
 32 };
 33 Point P[MAXN];
 34 int dcmp(double x)
 35 {
 36     if(fabs(x) < eps)
 37         return 0;
 38     else
 39         return x < 0 ? -1 : 1;
 40 }
 41 Point operator - (Point A, Point B){
 42     return Point(A.x-B.x, A.y-B.y);
 43 }
 44 Point operator + (Point A, Point B){
 45     return Point(A.x+B.x, A.y+B.y);
 46 }
 47 Point operator * (Point A, double p){
 48     return Point(A.x*p, A.y*p);;
 49 }
 50 double Cross(Point A, Point B){
 51     return A.x*B.y - A.y*B.x;
 52 }
 53 double Dot(Point A, Point B){
 54     return A.x*B.x + A.y*B.y;
 55 }
 56 double Dis(Point A, Point B){
 57     return sqrt((A.x-B.x)*(A.x-B.x) + (A.y-B.y)*(A.y-B.y));
 58 }
 59 bool operator == (Point A, Point B){
 60     return dcmp(A.x-B.x) == 0 && dcmp(A.y-B.y) == 0;
 61 }
 62 bool cmp(Point A, Point B)//按极角升序排序,若角度相等距离小的在前面
 63 {
 64     double temp = Cross(A-P[0], B-P[0]);
 65     if(dcmp(temp) > 0) return true;
 66     if(dcmp(temp) == 0 && dcmp(Dis(P[0], A) - Dis(P[0], B)) < 0) return true;
 67     return false;
 68 }
 69 int Stack[MAXN], top;//下标从0开始计数到top
 70 void input(int n)
 71 {
 72     scanf("%lf%lf", &P[0].x, &P[0].y);
 73     double xx = P[0].x, yy = P[0].y;
 74     int id = 0;//找到y坐标最小的点,若有多个选择x坐标最小的记录下标
 75     for(int i = 1; i < n; i++)
 76     {
 77         scanf("%lf%lf", &P[i].x, &P[i].y);
 78         if(P[i].y < yy || (P[i].y == yy && P[i].x < xx))
 79         {
 80             xx = P[i].x;
 81             yy = P[i].y;
 82             id = i;
 83         }
 84     }
 85     Point T;
 86     T = P[0]; P[0] = P[id]; P[id] = T;
 87     sort(P+1, P+n, cmp);//极角排序
 88 }
 89 void Graham(int n)
 90 {
 91     if(n == 1){ top = 0; Stack[0] = 0;}
 92     else if(n == 2)
 93     {
 94         top = 1;
 95         Stack[0] = 0;
 96         Stack[1] = 1;
 97     }
 98     else
 99     {
100         for(int i = 0; i <= 1; i++)
101             Stack[i] = i;
102         top = 1;
103         for(int i = 2; i < n; i++)
104         {   //如果和上一条边成左旋关系,压栈继续;反之一直弹栈直到和栈顶两点的边成左转关系,压栈继续。
105             while(top > 0 && dcmp(Cross(P[Stack[top]]-P[Stack[top-1]], P[i]-P[Stack[top-1]])) <= 0) top--;
106             top++;
107             Stack[top] = i;
108         }
109     }
110 }
111 int main()
112 {
113     int n;
114     input(n);
115     Graham(n);
116     return 0;
117 }
View Code

3.6 计算几何模板

  1 #include<iostream>
  2 #include<cmath>
  3 #include<cstdio>
  4 #include<algorithm>
  5 #define INF 1E200
  6 using namespace std;
  7 const double PI  = 3.14159265;//||acos(-1)
  8 const double eps=0.0000000001;
  9 struct Point //
 10 {
 11     double x,y;
 12     Point (double a=0,double b=0):x(a),y(b) {}
 13 };
 14 struct Line_segment //线段
 15 {
 16     Point s,e;
 17     Line_segment() {}
 18     Line_segment(Point a,Point b):s(a),e(b) {}
 19 };
 20 struct Line //直线
 21 {
 22     double A,B,C;
 23     Line(double A=1,double B=-1,double C=0):A(A),B(B),C(C) {}
 24 };
 25 inline double Max(double a,double b)
 26 {
 27     return a>b?a:b;
 28 }
 29 inline double Min(double a,double b)
 30 {
 31     return a<b?a:b;
 32 }
 33  
 34 //计算几何 开始!
 35 double Dist(Point a,Point b) //1.两点之间距离
 36 {
 37     return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
 38 }
 39 bool equal_Point(Point a,Point b) //2.判断两点是否重合
 40 {
 41     return fabs(a.x-b.x)<eps&&fabs(a.y-b.y)<eps;
 42 }
 43 double multiply(Point sp,Point  ep,Point op) //3.叉积//要判断点在直线哪一侧时,sp,ep为线段或者直线上两点,op为判断的点
 44 {
 45     /******************************************************************************
 46     r=multiply(sp,ep,op),得到(sp-op) 和 ( ep-op)的叉积
 47     r>0; ep在矢量op sp的逆时针方向//点在直线右边
 48     r=0;op sp ep 三点共线;
 49     r<0;ep在矢量op sp的顺时针方向//点在直线左边
 50     *******************************************************************************/
 51     return((sp.x-op.x)*(ep.y-op.y)-(ep.x-op.x)*(sp.y-op.y));
 52 }
 53 double dotmultiply(Point p1,Point p2,Point p0) //4.点积
 54 {
 55     /******************************************************************************
 56     r=dotmultiply(p1,p2,op),得到矢量(p1-op)和(p2-op)的点积,如果两个矢量都非零矢量
 57     r<0:两矢量夹角为钝角;
 58     r=0:两矢量夹角为直角;
 59     r>0:两矢量夹角为锐角;
 60     *******************************************************************************/
 61     return (p1.x-p0.x)*(p2.x-p0.x)+(p1.y-p0.y)*(p2.y-p0.y);
 62 }
 63 bool online(Line_segment l,Point p)//5.判断点p是否在线段l上 +3
 64 {
 65     /******************************************************************************
 66     判断点p是否在线段l上
 67     条件:(p在线段l所在的直线上) && (点p在以线段l为对角线的矩形内)
 68     *******************************************************************************/
 69     return( (multiply(l.e,p,l.s)==0) &&( ( (p.x-l.s.x)*(p.x-l.e.x)<=0 )&&( (p.y-l.s.y)*(p.y-l.e.y)<=0 ) ) );
 70 }
 71 Point Rotate(Point o,double alpha,Point p) // 6.返回点p以点o为圆心逆时针旋转alpha(单位:弧度)后所在的位置
 72 {
 73     Point tp;
 74     p.x-=o.x;
 75     p.y-=o.y;
 76     tp.x=p.x*cos(alpha)-p.y*sin(alpha)+o.x;
 77     tp.y=p.y*cos(alpha)+p.x*sin(alpha)+o.y;
 78     return tp;
 79 }
 80 double angle(Point o,Point s,Point e) //7.返回顶角在o点,起始边为os,终止边为oe的夹角(单位:弧度)
 81 {
 82     /******************************************************************************
 83        返回顶角在o点,起始边为os,终止边为oe的夹角(单位:弧度)
 84     角度小于pi,返回正值
 85     角度大于pi,返回负值
 86     可以用于求线段之间的夹角
 87     原理:
 88     r = dotmultiply(s,e,o) / (dist(o,s)*dist(o,e))
 89     r'= multiply(s,e,o)
 90     r >= 1 angle = 0;
 91     r <= -1 angle = -PI
 92     -1<r<1 && r'>0 angle = arccos(r)
 93     -1<r<1 && r'<=0 angle = -arccos(r)
 94     ********************************************************************************/
 95     double cosfi,fi,norm;
 96     double dsx = s.x - o.x;
 97     double dsy = s.y - o.y;
 98     double dex = e.x - o.x;
 99     double dey = e.y - o.y;
100     cosfi=dsx*dex+dsy*dey;
101     norm=(dsx*dsx+dsy*dsy)*(dex*dex+dey*dey);
102     cosfi /= sqrt( norm );
103     if (cosfi >=  1.0 ) return 0;
104     if (cosfi <= -1.0 ) return -3.1415926;
105     fi=acos(cosfi);
106     if (dsx*dey-dsy*dex>0) return fi;      // 说明矢量os 在矢量 oe的顺时针方向
107     return -fi;
108 }
109 double relation(Point p,Line_segment l) //8.判断点与线段的关系
110 {
111     /******************************************************************************
112     判断点与线段的关系,用途很广泛
113     本函数是根据下面的公式写的,P是点C到线段AB所在直线的垂足
114             AC dot AB
115     r =     ---------
116              ||AB||^2
117          (Cx-Ax)(Bx-Ax) + (Cy-Ay)(By-Ay)
118       = -------------------------------
119                       L^2
120     r has the following meaning:
121     r=0      P = A
122     r=1      P = B
123     r<0   P is on the backward extension of AB
124     r>1      P is on the forward extension of AB
125     0<r<1  P is interior to AB
126     ********************************************************************************/
127     Line_segment tl;
128     tl.s=l.s;
129     tl.e=p;
130     return dotmultiply(tl.e,l.e,l.s)/(Dist(l.s,l.e)*Dist(l.s,l.e));
131 }
132 Point perpendicular(Point p,Line_segment l) //9.求点C到线段AB所在直线的垂足 P
133 {
134     /******************************************************************************
135        求点C到线段AB所在直线的垂足 P
136        *******************************************************************************/
137     double r=relation(p,l);
138     Point tp;
139     tp.x=l.s.x+r*(l.e.x-l.s.x);
140     tp.y=l.s.y+r*(l.e.y-l.s.y);
141     return tp;
142 }
143 double ptolinesegdist(Point p,Line_segment l,Point &np) //10.求点p到线段l的最短距离,并返回线段上距该点最近的点np
144 {
145     /******************************************************************************
146        求点p到线段l的最短距离,并返回线段上距该点最近的点np
147     注意:np是线段l上到点p最近的点,不一定是垂足
148     *******************************************************************************/
149     double r=relation(p,l);
150     if(r<0)
151     {
152         np=l.s;
153         return Dist(p,l.s);
154     }
155     if(r>1)
156     {
157         np=l.e;
158         return Dist(p,l.e);
159     }
160     np=perpendicular(p,l);
161     return Dist(p,np);
162 }
163 double ptoldist(Point p,Line_segment l) // 11.求点p到线段l所在直线的距离,请注意本函数与上个函数的区别
164 {
165     return abs(multiply(p,l.e,l.s))/Dist(l.s,l.e);
166 }
167 double ptopointset(int vcount,Point pointset[],Point p,Point &q) //12.计算点到折线集的最近距离,并返回最近点.
168 {
169     /******************************************************************************
170      计算点到折线集的最近距离,并返回最近点.
171     注意:调用的是ptolineseg()函数
172     *******************************************************************************/
173     int i;
174     double cd=double(INF),td;
175     Line_segment l;
176     Point tq,cq;
177     for(i=0; i<vcount-1; i++)
178     {
179         l.s=pointset[i];
180         l.e=pointset[i+1];
181         td=ptolinesegdist(p,l,tq);
182         if(td<cd)
183         {
184             cd=td;
185             cq=tq;
186         }
187     }
188     q=cq;
189     return cd;
190 }
191 bool CircleInsidePolygon(int vcount,Point center,double radius,Point polygon[]) //13.判断圆是否在多边形内.ptolineseg()函数的应用
192 {
193     Point q;
194     double d;
195     q.x=0;
196     q.y=0;
197     d=ptopointset(vcount,polygon,center,q);
198     if(d>radius||fabs(d-radius)<eps)
199         return true;//若不考虑相切的情况,去掉 fabs(d-radius)<eps
200  
201     else
202         return false;
203 }
204 double cosine(Line_segment l1,Line_segment l2)   //14.返回两个 矢量 l1和l2的夹角的余弦
205 {
206     /******************************************************************************
207     返回两个矢量l1和l2的夹角的余弦(-1 --- 1)注意:如果想从余弦求夹角的话,注意反余弦函数的定义域是从 0到pi
208     *******************************************************************************/
209     return (((l1.e.x-l1.s.x)*(l2.e.x-l2.s.x) +(l1.e.y-l1.s.y)*(l2.e.y-l2.s.y))/(Dist(l1.e,l1.s)*Dist(l2.e,l2.s)));
210 }
211 double lsangle(Line_segment l1,Line_segment l2)  // 15.返回线段l1与l2之间的夹角 单位:弧度 范围(-pi,pi)
212 {
213     Point o,s,e;
214     o.x=o.y=0;
215     s.x=l1.e.x-l1.s.x;
216     s.y=l1.e.y-l1.s.y;
217     e.x=l2.e.x-l2.s.x;
218     e.y=l2.e.y-l2.s.y;
219     return angle(o,s,e);
220 }
221 bool intersect(Line_segment u,Line_segment v) // 16.如果线段u和v相交(包括相交在端点处)时,返回true
222 {
223     /******************************************************************************
224     如果线段u和v相交(包括相交在端点处)时,返回true
225     判断P1P2跨立Q1Q2的依据是: ( P1 - Q1 ) x ( Q2 - Q1 ) x ( Q2 - Q1 ) x ( P2 - Q1 ) >= 0
226     判断Q1Q2跨立P1P2的依据是: ( Q1 - P1 ) x ( P2 -  P1 ) x ( P2 - P1 ) x ( Q2 - P1 ) >= 0
227     *******************************************************************************/
228     return((Max(u.s.x,u.e.x)>=Min(v.s.x,v.e.x))&&                     //排斥实验
229            (Max(v.s.x,v.e.x)>=Min(u.s.x,u.e.x))&&
230            (Max(u.s.y,u.e.y)>=Min(v.s.y,v.e.y))&&
231            (Max(v.s.y,v.e.y)>=Min(u.s.y,u.e.y))&&
232            (multiply(v.s,u.e,u.s)*multiply(u.e,v.e,u.s)>=0)&&         //跨立实验
233            (multiply(u.s,v.e,v.s)*multiply(v.e,u.e,v.s)>=0));
234 }
235 bool intersect_A(Line_segment u,Line_segment v) // 17.(线段u和v相交)&&(交点不是端点)时返回true
236 {
237     return ((intersect(u,v))&&
238             (!online(u,v.s))&&
239             (!online(u,v.e))&&
240             (!online(v,u.e))&&
241             (!online(v,u.s)));
242 }
243 bool intersect_l(Line_segment u,Line_segment v)// 18.线段v所在直线与线段u相交时返回true
244 {
245     /******************************************************************************
246     线段v所在直线与线段u相交时返回true;方法;判断线段u是否跨立线段v
247     *******************************************************************************/
248     return multiply(u.s,v.e,v.s)*multiply(v.e,u.e,v.s)>=0;
249 }
250 Line makeline(Point p1,Point p2)   // 19.根据已知两点坐标,求过这两点的直线解析方程
251 {
252     /******************************************************************************
253     根据已知两点坐标,求过这两点的直线解析方程Ax+By+C=0 (A>=0)
254     *******************************************************************************/
255     Line tl;
256     int sign = 1;
257     tl.A=p2.y-p1.y;
258     if(tl.A<0)
259     {
260         sign = -1;
261         tl.A=sign*tl.A;
262     }
263     tl.B=sign*(p1.x-p2.x);
264     tl.C=sign*(p1.y*p2.x-p1.x*p2.y);
265     return tl;
266 }
267 double slope(Line l)   // 20.根据直线解析方程返回直线的斜率k,  水平线返回 0, 竖直线返回 1e200
268 {
269     if(abs(l.A) < 1e-20)
270         return 0;
271     if(abs(l.B) < 1e-20)
272         return INF;
273     return -(l.A/l.B);
274 }
275 double alpha(Line l)   //21. 返回直线的倾斜角 alpha ( 0 - pi)
276 {
277     if(abs(l.A)< eps)
278         return 0;
279     if(abs(l.B)< eps)
280         return PI/2;
281     double k=slope(l);
282     if(k>0)
283         return atan(k);
284     else
285         return PI+atan(k);
286 }
287 Point symmetry(Line l,Point p) //22. 求点p关于直线l的对称点
288 {
289     Point tp;
290     tp.x=((l.B*l.B-l.A*l.A)*p.x-2*l.A*l.B*p.y-2*l.A*l.C)/(l.A*l.A+l.B*l.B);
291     tp.y=((l.A*l.A-l.B*l.B)*p.y-2*l.A*l.B*p.x-2*l.B*l.C)/(l.A*l.A+l.B*l.B);
292     return tp;
293 }
294 bool lineintersect(Line l1,Line l2,Point &p) // 23.两直线相交返回true并返回交点p,不相交则返回false
295 {
296     double d=l1.A*l2.B-l2.A*l1.B;
297     if(abs(d)<eps) // 不相交
298         return false;
299     p.x = (l2.C*l1.B-l1.C*l2.B)/d;
300     p.y = (l2.A*l1.C-l1.A*l2.C)/d;
301     return true;
302 }
303 bool intersection(Line_segment l1,Line_segment l2,Point &inter)   // 24.如果线段l1和l2相交,返回true且交点由(inter)返回,否则返回false
304 {
305     Line ll1,ll2;
306     ll1=makeline(l1.s,l1.e);
307     ll2=makeline(l2.s,l2.e);
308     if(intersect(l1,l2)==1)
309     {
310         lineintersect(ll1,ll2,inter);
311         return true;
312     }
313     else
314         return false;
315 }
316 /*******************************************************************************/
317 bool point_in_circle(Point o,double r,Point p)   //25. 返回值:点p在圆内(包括边界)时,返回true
318 {
319     /******************************************************************************
320     参数o为圆心,r为半径,p为判断的点
321     返回值:点p在圆内(包括边界)时,返回true
322     *******************************************************************************/
323     double d2=(p.x-o.x)*(p.x-o.x)+(p.y-o.y)*(p.y-o.y);
324     double r2=r*r;
325     return d2<r2||abs(d2-r2)<eps;
326 }
327  
328 bool cocircle(Point p1,Point p2,Point p3,Point &q,double &r) //26.三点确定一个圆,不能构成圆返回false
329 {
330     /******************************************************************************
331     用 途 :求不共线的三点确定一个圆
332     输 入 :三个点p1,p2,p3
333     返回值 :如果三点共线,返回false;反之,返回true。圆心由q返回,半径由r返回
334     *******************************************************************************/
335     double x12=p2.x-p1.x;
336     double y12=p2.y-p1.y;
337     double x13=p3.x-p1.x;
338     double y13=p3.y-p1.y;
339     double z2=x12*(p1.x+p2.x)+y12*(p1.y+p2.y);
340     double z3=x13*(p1.x+p3.x)+y13*(p1.y+p3.y);
341     double d=2.0*(x12*(p3.y-p2.y)-y12*(p3.x-p2.x));
342     if(abs(d)<eps) //共线,圆不存在
343         return false;
344     q.x=(y13*z2-y12*z3)/d;
345     q.y=(x12*z3-x13*z2)/d;
346     r=Dist(p1,q);
347     return true;
348 }
349 int CircleRelation(Point p1, double r1, Point p2, double r2) //27.两圆位置关系
350 {
351     /******************************************************************************
352     相离:return 1
353     外切:return 2
354     相交:return 3
355     内切:return 4
356     内含:return 5
357     *******************************************************************************/
358     double d = sqrt( (p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y) );
359     if( fabs(d-r1-r2) < eps ) // 必须保证前两个if先被判定!
360         return 2;
361     if( fabs(d-fabs(r1-r2)) < eps )
362         return 4;
363     if( d > r1+r2 )
364         return 1;
365     if( d < fabs(r1-r2) )
366         return 5;
367     if( fabs(r1-r2) < d && d < r1+r2 )
368         return 3;
369     return 0; // indicate an error!未知错误
370 }
371 double P2planeDist(double x, double y, double z, double a, double b, double c, double d) //28.空间 点到平面距离
372 {
373     /******************************************************************************
374     空间点到平面的距离,平面用一般式表示ax+by+cz+d=0
375     *******************************************************************************/
376     return fabs(a*x+b*y+c*z+d) / sqrt(a*a+b*b+c*c);
377 }
378 bool SameSide(Point p1, Point p2, Line line) //29.点在直线同侧返回true
379 {
380     return (line.A * p1.x + line.B * p1.y + line.C) *
381            (line.A * p2.x + line.B * p2.y + line.C) > 0;
382 }
383 void  c2point(Point p1,double r1,Point p2,double r2,Point &rp1,Point &rp2) //30.两个圆(已判断为相交或相切)的交点rp1,rp2
384 {
385     double a,b,r;
386     a=p2.x-p1.x;
387     b=p2.y-p1.y;
388     r=(a*a+b*b+r1*r1-r2*r2)/2;
389     if(a==0&&b!=0)
390     {
391         rp1.y=rp2.y=r/b;
392         rp1.x=sqrt(r1*r1-rp1.y*rp1.y);
393         rp2.x=-rp1.x;
394     }
395     else if(a!=0&&b==0)
396     {
397         rp1.x=rp2.x=r/a;
398         rp1.y=sqrt(r1*r1-rp1.x*rp2.x);
399         rp2.y=-rp1.y;
400     }
401     else if(a!=0&&b!=0)
402     {
403         double delta;
404         delta=b*b*r*r-(a*a+b*b)*(r*r-r1*r1*a*a);
405         rp1.y=(b*r+sqrt(delta))/(a*a+b*b);
406         rp2.y=(b*r-sqrt(delta))/(a*a+b*b);
407         rp1.x=(r-b*rp1.y)/a;
408         rp2.x=(r-b*rp2.y)/a;
409     }
410     rp1.x+=p1.x;
411     rp1.y+=p1.y;
412     rp2.x+=p1.x;
413     rp2.y+=p1.y;
414 }
415 double c2area(Point p1,double r1,Point p2,double r2) //31.两相交圆公共面积 +30
416 {
417     double TEMP;
418     Point rp1,rp2,rp;
419     c2point(p1,r1,p2,r2,rp1,rp2);
420     if(r1>r2) //保证r2>r1
421     {
422         rp=p1;
423         p1=p2;
424         p2=rp;
425         TEMP=r1;
426         r1=r2;
427         r2=TEMP;
428     }
429     double a,b,rr;
430     a=p1.x-p2.x;
431     b=p1.y-p2.y;
432     rr=sqrt(a*a+b*b);
433     double dx1,dy1,dx2,dy2;
434     double sita1,sita2;
435     dx1=rp1.x-p1.x;
436     dy1=rp1.y-p1.y;
437     dx2=rp2.x-p1.x;
438     dy2=rp2.y-p1.y;
439     sita1=acos((dx1*dx2+dy1*dy2)/r1/r1);
440     dx1=rp1.x-p2.x;
441     dy1=rp1.y-p2.y;
442     dx2=rp2.x-p2.x;
443     dy2=rp2.y-p2.y;
444     sita2=acos((dx1*dx2+dy1*dy2)/r2/r2);
445     double s=0;
446     if(rr<r2)//相交弧为优弧
447         s=r1*r1*(PI-sita1/2+sin(sita1)/2)+r2*r2*(sita2-sin(sita2))/2;
448     else//相交弧为劣弧
449         s=(r1*r1*(sita1-sin(sita1))+r2*r2*(sita2-sin(sita2)))/2;
450  
451  
452     return s;
453 }
454  
455 int clpoint(Point p,double r,double a,double b,double c,Point &rp1,Point &rp2) //32.圆和直线(ax+by+c=0,a>=0)关系
456 {
457     /******************************************************************************
458     相离 return 0
459     相切 return 1
460     相交 return 2
461     *******************************************************************************/
462     int res=0;
463     c=c+a*p.x+b*p.y;
464     double tmp;
465     if(a==0&&b!=0)
466     {
467         tmp=-c/b;
468         if(r*r<tmp*tmp)
469             res=0;
470         else if(r*r==tmp*tmp)
471         {
472             res=1;
473             rp1.y=tmp;
474             rp1.x=0;
475         }
476         else
477         {
478             res=2;
479             rp1.y=rp2.y=tmp;
480             rp1.x=sqrt(r*r-tmp*tmp);
481             rp2.x=-rp1.x;
482         }
483     }
484     else if(a!=0&&b==0)
485     {
486         tmp=-c/a;
487         if(r*r<tmp*tmp)
488             res=0;
489         else if(r*r==tmp*tmp)
490         {
491             res=1;
492             rp1.x=tmp;
493             rp1.y=0;
494         }
495         else
496         {
497             res=2;
498             rp1.x=rp2.x=tmp;
499             rp1.y=sqrt(r*r-tmp*tmp);
500             rp2.y=-rp1.y;
501         }
502     }
503     else if(a!=0&&b!=0)
504     {
505         double delta;
506         delta=b*b*c*c-(a*a+b*b)*(c*c-a*a*r*r);
507         if(delta<0)
508             res=0;
509         else if(delta==0)
510         {
511             res=1;
512             rp1.y=-b*c/(a*a+b*b);
513             rp1.x=(-c-b*rp1.y)/a;
514         }
515         else
516         {
517             res=2;
518             rp1.y=(-b*c+sqrt(delta))/(a*a+b*b);
519             rp2.y=(-b*c-sqrt(delta))/(a*a+b*b);
520             rp1.x=(-c-b*rp1.y)/a;
521             rp2.x=(-c-b*rp2.y)/a;
522         }
523     }
524     rp1.x+=p.x;
525     rp1.y+=p.y;
526     rp2.x+=p.x;
527     rp2.y+=p.y;
528     return res;
529 }
530 void incircle(Point p1,Point p2,Point p3,Point &rp,double &r) // 33.三角形内切圆
531 {
532     double dx31,dy31,dx21,dy21,d31,d21,a1,b1,c1;
533     dx31=p3.x-p1.x;
534     dy31=p3.y-p1.y;
535     dx21=p2.x-p1.x;
536     dy21=p2.y-p1.y;
537     d31=sqrt(dx31*dx31+dy31*dy31);
538     d21=sqrt(dx21*dx21+dy21*dy21);
539     a1=dx31*d21-dx21*d31;
540     b1=dy31*d21-dy21*d31;
541     c1=a1*p1.x+b1*p1.y;
542     double dx32,dy32,dx12,dy12,d32,d12,a2,b2,c2;
543     dx32=p3.x-p2.x;
544     dy32=p3.y-p2.y;
545     dx12=-dx21;
546     dy12=-dy21;
547     d32=sqrt(dx32*dx32+dy32*dy32);
548     d12=d21;
549     a2=dx12*d32-dx32*d12;
550     b2=dy12*d32-dy32*d12;
551     c2=a2*p2.x+b2*p2.y;
552     rp.x=(c1*b2-c2*b1)/(a1*b2-a2*b1);
553     rp.y=(c2*a1-c1*a2)/(a1*b2-a2*b1);
554     r=fabs(dy21*rp.x-dx21*rp.y+dx21*p1.y-dy21*p1.x)/d21;
555 }
556  
557 void cutpoint(Point p,double r,Point sp,Point &rp1,Point &rp2) //34.过圆外一点的直线与圆的两个切点(p为圆心,r为圆半径,点sp为圆外一点)
558 {
559     Point p2;
560     p2.x=(p.x+sp.x)/2;
561     p2.y=(p.y+sp.y)/2;
562     double dx2,dy2,r2;
563     dx2=p2.x-p.x;
564     dy2=p2.y-p.y;
565     r2=sqrt(dx2*dx2+dy2*dy2);
566     c2point(p,r,p2,r2,rp1,rp2);
567 }
568  
569 void DoneSq(Point a, Point c,Point& b,Point &d)//35.已知正方形对角线上两顶点(a和c),求另两点(b和d);
570 {
571     double x,y,mx,my;
572     mx = (a.x+c.x)/2.0;
573     my = (a.y+c.y)/2.0;
574     x = a.x - mx;
575     y = a.y - my;
576     b.x = -y + mx;
577     b.y = x + my;
578     x = c.x - mx;
579     y = c.y - my;
580     d.x = - y + mx;
581     d.y = x + my;
582 }
583 void makeline2(Line& L,const Point& a,const double& k)// 36. 根据一点坐标及其斜率k(已证实存在),求这条直线的解析方程
584 {
585     L.A=k;
586     L.B=-1;
587     L.C=a.y-k*a.x;
588 }
589  
590 void min_cover_circle(Point *p,int n,Point &c,double &r)// 37.随机增量算法求最小覆盖圆 (点/点的个数/圆心/半径)
591 {
592     random_shuffle(p,p+n);
593     c=p[0];
594     r=0;
595     for(int i=1; i<n; i++)
596     {
597         if(Dist(p[i],c)>r+eps)
598         {
599             c=p[i];
600             r=0;
601             for(int j=0; j<i; j++)
602                 if(Dist(p[j],c)>r+eps)
603                 {
604                     c.x=(p[i].x+p[j].x)/2;
605                     c.y=(p[i].y+p[j].y)/2;
606                     r=Dist(p[j],c);
607                     for(int k=0; k<j; k++)
608                         if(Dist(p[k],c)>r+eps)
609                         {
610                             cocircle(p[i],p[j],p[k],c,r);
611                         }
612                 }
613         }
614     }
615 }
616 bool InsideConvexPolygon(int vcount,Point polygon[],Point q) // 38.判断点q是否在凸多边形内//多边形顶点<=2时返回0
617 {
618     if(vcount<3) return 0;
619     Point p;
620     Line_segment l;
621     int i;
622     p.x=0;
623     p.y=0;
624     for(i=0; i<vcount; i++) // 寻找一个肯定在多边形polygon内的点p;多边形顶点平均值
625     {
626         p.x+=polygon[i].x;
627         p.y+=polygon[i].y;
628     }
629     p.x /= vcount;
630     p.y /= vcount;
631  
632     for(i=0; i<vcount; i++)
633     {
634         l.s=polygon[i];
635         l.e=polygon[(i+1)%vcount];
636         if(multiply(p,l.e,l.s)*multiply(q,l.e,l.s)<0) /* 点p和点q在边l的两侧,说明点q肯定在多边形外 */
637             break;
638     }
639     return (i==vcount);
640 }
641  
642 double Getarea(int n,Point top[])// 39.计算顶点已按逆时针或顺时针排好的 多边形面积,
643 {
644     Point p=top[0];
645     double s=0;
646     for(int i=0; i<n-1; i++)
647     {
648         s+=top[i].x*top[i+1].y-top[i].y*top[i+1].x;
649     }
650     s+=top[n-1].x*top[0].y-top[n-1].y*top[0].x;
651     return fabs(s/2);
652 }
653 bool cmp1(Point a,Point b)//凸包排序方法
654 {
655     if(a.x == b.x)
656         return a.y < b.y;
657     return a.x < b.x;
658 }
659  
660 int graham(Point pnt[],int n,Point res[])//40.求凸包,pnt为点集,n为点的个数,res为凸包上的点,返回值为凸包点的个数
661 {
662     sort(pnt,pnt+n,cmp1);
663     int m=0, i, k;
664     for(i = 0; i < n; i++)
665     {
666         while(m>1 && multiply(res[m-1],pnt[i],res[m-2])<=0)
667             m--;
668         res[m++]=pnt[i];
669     }
670     k = m;
671     for(i = n-2; i >= 0; i--)
672     {
673         while(m>k && multiply(res[m-1],pnt[i],res[m-2])<=0)
674             m--;
675         res[m++]=pnt[i];
676     }
677     if(n > 1)//起始点重复。
678         m--;
679     return m;
680 }
681 double area1(Point c,double r,int n)//41.圆与n边形相交面积 c为圆心,r为半径 数组P为含n个点的数组
682 {
683     Point a,b;
684     double A,B,C,x,y,tS,Ans=0;
685     for(int i=0; i<n; i++)
686     {
687         a=P[i];    //数组P为多边形顶点数组
688         b=P[(i+1)%n];
689         A=Dist(b,c);
690         B=Dist(a,c);
691         C=Dist(b,a);
692         if(A<r&&B<r)
693             Ans+= multiply(a,b,c)/2;
694         else if(A<r&&B>=r)
695         {
696             x=(dotmultiply(a,c,b)+sqrt(r*r*C*C-multiply(a,c,b)*multiply(a,c,b)))/C;
697             tS=multiply(a,b,c)/2;
698             Ans+= asin(tS*(1-x/C)*2/r/B*(1-eps))*r*r/2+tS*x/C;
699         }
700         else if(A>=r&&B<r)
701         {
702             y=(dotmultiply(b,c,a)+sqrt(r*r*C*C-multiply(b,c,a)*multiply(b,c,a)))/C;
703             tS=multiply(a,b,c)/2;
704             Ans+= asin(tS*(1-y/C)*2/r/A*(1-eps))*r*r/2+tS*y/C;
705         }
706         else if(fabs(multiply(a,b,c))>=r*C||dotmultiply(b,c,a)<=0||dotmultiply(a,c,b)<=0)
707         {
708             if(dotmultiply(a,b,c)<0)
709                 if(multiply(a,b,c)<0)
710                     Ans+= (-acos(-1.0)-asin(multiply(a,b,c)/A/B*(1-eps)))*r*r/2;
711                 else Ans+= (acos(-1.0)-asin(multiply(a,b,c)/A/B*(1-eps)))*r*r/2;
712             else Ans+= asin(multiply(a,b,c)/A/B*(1-eps))*r*r/2;
713         }
714         else
715         {
716             x=(dotmultiply(a,c,b)+sqrt(r*r*C*C-multiply(a,c,b)*multiply(a,c,b)))/C;
717             y=(dotmultiply(b,c,a)+sqrt(r*r*C*C-multiply(b,c,a)*multiply(b,c,a)))/C;
718             tS=multiply(a,b,c)/2;
719             Ans+= (asin(tS*(1-x/C)*2/r/B*(1-eps))+asin(tS*(1-y/C)*2/r/A*(1-eps)))*r*r/2+tS*((y+x)/C-1);
720         }
721     }
722     return Ans;
723 }
724 int main()
725 {
726     double a,b,c,d;
727     Point m(1,1),n(2,2);
728     Line_segment w(m,n);
729     while(~scanf("%lf %lf",&a,&b))
730     {
731         Point A(a,b);
732         if(online(w,A)) printf("yes\n");
733         else printf("n0\n");
734     }
735     return 0;
736 }
View Code

 3.7 孙子定理 中国剩余定理

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 using namespace std;
 6 
 7 typedef long long ll;
 8 ll a[100005],r[100005];
 9 int n;
10 
11 ll exgcd(ll a,ll b,ll &x,ll &y){
12     if(b==0) return x=1,y=0,a;
13     ll tmp=exgcd(b,a%b,y,x);
14     y-=a/b*x;
15     return tmp;
16 }
17 
18 ll solve(){
19     ll M=a[1],R=r[1],x,y,d;
20     for(int i=2;i<=n;i++){
21         d=exgcd(M,a[i],x,y);
22         if((R-r[i])%d!=0) return -1;
23         x=(R-r[i])/d*x%a[i];
24         R-=x*M;
25         M=M/d*a[i];
26         R%=M;
27     }
28     return (R%M+M)%M;
29 }
30 
31 int main(){
32     while(~scanf("%d",&n)){
33         for(int i=1;i<=n;i++)scanf("%lld%lld",&a[i],&r[i]);
34         printf("%lld\n",solve());
35     }
36     return 0;
37 }
View Code

 3.8 辛普森积分

 1 double simpson(double a,double b)
 2 {
 3     double c = a + (b-a)/2;
 4     return (F(a) + 4*F(c) + F(b))*(b-a)/6;
 5 }
 6 double asr(double a,double b,double eps,double A)
 7 {
 8     double c = a + (b-a)/2;
 9     double L = simpson(a,c), R = simpson(c,b);
10     if(fabs(L + R - A) <= 15*eps)return L + R + (L + R - A)/15.0;
11     return asr(a,c,eps/2,L) + asr(c,b,eps/2,R);
12 }
13 double asr(double a,double b,double eps)
14 {
15     return asr(a,b,eps,simpson(a,b));
16 }
View Code

 3.9 高斯消元求解线性方程组

  1  #include<stdio.h>
  2     #include<algorithm>
  3     #include<iostream>
  4     #include<string.h>
  5     #include<math.h>
  6     using namespace std;
  7     const int MAXN=50;
  8     int a[MAXN][MAXN];//增广矩阵
  9     int x[MAXN];//解集
 10     bool free_x[MAXN];//标记是否是不确定的变元
 11     int gcd(int a,int b){
 12         if(b == 0) return a; else return gcd(b,a%b);
 13     }
 14     inline int lcm(int a,int b){
 15         return a/gcd(a,b)*b;//先除后乘防溢出
 16     }
 17     // 高斯消元法解方程组(Gauss-Jordan elimination).(-2表示有浮点数解,但无整数解,
 18     //-1表示无解,0表示唯一解,大于0表示无穷解,并返回自由变元的个数)
 19     //有equ个方程,var个变元。增广矩阵行数为equ,分别为0到equ-1,列数为var+1,分别为0到var.
 20     int Gauss(int equ,int var){
 21         int i,j,k;
 22         int max_r;// 当前这列绝对值最大的行.
 23         int col;//当前处理的列
 24         int ta,tb;
 25         int LCM;
 26         int temp;
 27         int free_x_num;
 28         int free_index;
 29 
 30         for(int i=0;i<=var;i++){
 31             x[i]=0;
 32             free_x[i]=true;
 33         }
 34 
 35         //转换为阶梯阵.
 36         col=0; // 当前处理的列
 37         for(k = 0;k < equ && col < var;k++,col++){// 枚举当前处理的行.
 38         // 找到该col列元素绝对值最大的那行与第k行交换.(为了在除法时减小误差)
 39             max_r=k;
 40             for(i=k+1;i<equ;i++){
 41                 if(abs(a[i][col])>abs(a[max_r][col])) max_r=i;
 42             }
 43             if(max_r!=k){// 与第k行交换.
 44                 for(j=k;j<var+1;j++) swap(a[k][j],a[max_r][j]);
 45             }
 46             if(a[k][col]==0){// 说明该col列第k行以下全是0了,则处理当前行的下一列.
 47                 k--;
 48                 continue;
 49             }
 50             for(i=k+1;i<equ;i++){// 枚举要删去的行.
 51                 if(a[i][col]!=0){
 52                     LCM = lcm(abs(a[i][col]),abs(a[k][col]));
 53                     ta = LCM/abs(a[i][col]);
 54                     tb = LCM/abs(a[k][col]);
 55                     if(a[i][col]*a[k][col]<0)tb=-tb;//异号的情况是相加
 56                     for(j=col;j<var+1;j++){
 57                         a[i][j] = a[i][j]*ta-a[k][j]*tb;
 58                     }
 59                 }
 60             }
 61         }
 62         // 1. 无解的情况: 化简的增广阵中存在(0, 0, ..., a)这样的行(a != 0).
 63         for (i = k; i < equ; i++){ // 对于无穷解来说,如果要判断哪些是自由变元,那么初等行变换中的交换就会影响,则要记录交换.
 64             if (a[i][col] != 0) return -1;
 65         }
 66         // 2. 无穷解的情况: 在var * (var + 1)的增广阵中出现(0, 0, ..., 0)这样的行,即说明没有形成严格的上三角阵.
 67         // 且出现的行数即为自由变元的个数.
 68         if (k < var){
 69             return var - k; // 自由变元有var - k个.
 70         }
 71         // 3. 唯一解的情况: 在var * (var + 1)的增广阵中形成严格的上三角阵.
 72         // 计算出Xn-1, Xn-2 ... X0.
 73         for (i = var - 1; i >= 0; i--){
 74             temp = a[i][var];
 75             for (j = i + 1; j < var; j++){
 76                 if (a[i][j] != 0) temp -= a[i][j] * x[j];
 77             }
 78             if (temp % a[i][i] != 0) return -2; // 说明有浮点数解,但无整数解.
 79             x[i] = temp / a[i][i];
 80         }
 81         return 0;
 82     }
 83     int main(void){
 84     //    freopen("in.txt", "r", stdin);
 85     //    freopen("out.txt","w",stdout);
 86         int i, j;
 87         int equ,var;
 88         while (scanf("%d %d", &equ, &var) != EOF){
 89             memset(a, 0, sizeof(a));
 90             for (i = 0; i < equ; i++){
 91                 for (j = 0; j < var + 1; j++){
 92                     scanf("%d", &a[i][j]);
 93                 }
 94             }
 95             int free_num = Gauss(equ,var);
 96             if (free_num == -1) printf("无解!\n");
 97             else if (free_num == -2) printf("有浮点数解,无整数解!\n");
 98             else if (free_num > 0){
 99                 printf("无穷多解! 自由变元个数为%d\n", free_num);
100                 for (i = 0; i < var; i++){
101                     if (free_x[i]) printf("x%d 是不确定的\n", i + 1);
102                     else printf("x%d: %d\n", i + 1, x[i]);
103                 }
104             }else{
105                 for (i = 0; i < var; i++){
106                     printf("x%d: %d\n", i + 1, x[i]);
107                 }
108             }
109             printf("\n");
110         }
111         return 0;
112     }
View Code

 3.10 整除分块

1 for(int l=1,r;l<=n;l=r+1)
2 {
3     r=n/(n/l);
4     ans+=(r-l+1)*(n/l);
5 }
View Code

 3.11 求莫比乌斯函数

 1 /*莫比乌斯函数具有两个性质:
 2 1.对于任意正整数nn,∑d|nμ(d)=[n=1]∑d|nμ(d)=[n=1]。([n=1][n=1]表示只有当n=1n=1成立时,返回值为11;否则,值为00;(这个就是用μμ是容斥系数的性质可以证明)(PS:这一条性质是莫比乌斯反演中最常用的)
 3 所有可以整除n的数的莫比乌斯函数之和等于0(特别的,n==1时等于1)。
 4 2.对于任意正整数nn,∑d|nμ(d)d=ϕ(n)n∑d|nμ(d)d=ϕ(n)n。(这个性质很奇妙,它把欧拉函数和莫比乌斯函数结合起来,或许我之后写杜教筛的学习笔记时会去证明吧)
 5 所有可以整除n的数d的莫比乌斯函数除以d的和等于 欧拉函数除以n的值
 6 */
 7 void get_mu(int n)
 8 {
 9     mu[1]=1;
10     for(int i=2;i<=n;i++)
11     {
12         if(!vis[i]){prim[++cnt]=i;mu[i]=-1;}
13         for(int j=1;j<=cnt&&prim[j]*i<=n;j++)
14         {
15             vis[prim[j]*i]=1;
16             if(i%prim[j]==0)break;
17             else mu[i*prim[j]]=-mu[i];
18         }
19     }
20  
View Code

 3.12 杜教筛

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 typedef long long ll;
 5 const int maxn = 1700010;
 6 int T, tot, prime[maxn], mu[maxn];
 7 map<int, ll> ans_mu;
 8 
 9 void sieve() {
10     fill(prime, prime + maxn, 1);
11     mu[1] = 1, tot = 0;
12     for (int i = 2; i < maxn; i++) {
13         if (prime[i]) {
14             prime[++tot] = i, mu[i] = -1;
15         }
16         for (int j = 1; j <= tot && i * prime[j] < maxn; j++) {
17             prime[i * prime[j]] = 0;
18             if (i % prime[j] == 0) {
19                 mu[i * prime[j]] = 0; break;
20             } else {
21                 mu[i * prime[j]] = -mu[i];
22             }
23         }
24     }
25     for (int i = 2; i < maxn; i++) mu[i] += mu[i - 1];
26 }
27 
28 ll calc_mu(int x) {
29     if (x < maxn) return mu[x];
30     if (ans_mu.count(x)) return ans_mu[x];
31     ll ans = 1;
32     for (ll i = 2, j; i <= x; i = j + 1) {
33         j = x / (x / i), ans -= (j - i + 1) * calc_mu(x / i);
34     }
35     return ans_mu[x] = ans;
36 }
37 
38 ll calc_phi(int x) {
39     ll ans = 0;
40     for (ll i = 1, j; i <= x; i = j + 1) {
41         j = x / (x / i), ans += (x / i) * (x / i) * (calc_mu(j) - calc_mu(i - 1));
42     }
43     return ((ans - 1) >> 1) + 1;
44 }
45 
46 int main() {
47     sieve();
48     scanf("%d", &T);
49     for (int i = 1, n; i <= T; i++) {
50         scanf("%d", &n);
51         printf("%lld %lld\n", calc_phi(n), calc_mu(n));
52     }
53     return 0;
54 }
View Code

 3.13 最大曼哈顿距离

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 #define N 100003
 6 #define inf 1e100
 7 double a[N][5];
 8 int n;
 9  
10 int main() {
11     while (scanf("%d", &n) == 1) {
12         for (int i=0; i<n; i++)
13             for (int j=0; j<5; j++) scanf("%lf", &a[i][j]);
14         double ans = 0, mi, mx, t;
15         for (int s=0; s<(1<<5); s++) {
16             mi = inf, mx = -inf;
17             for (int i=0; i<n; i++) {
18                 t = 0;
19                 for (int j=0; j<5; j++)
20                     if ((1<<j) & s) t += a[i][j];
21                     else t -= a[i][j];
22                 mi = min(mi, t);
23                 mx = max(mx, t);
24             }
25             ans = max(ans, mx-mi);
26         }
27         printf("%.2lf\n", ans);
28     }
29     return 0;
30 }
View Code

 

 

 

 

 

四.技巧

4.1 imos累积和法

 1 //http://www.hankcs.com/program/algorithm/imos_method.html
 2 //算法用于计算二维平面最大高度点,原理左上右下标1,左下右上标-1,累加求最大。
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <bits/stdc++.h>
 6 using namespace std;
 7 #define  W  6
 8 #define  H  6
 9 #define  N  4
10 // 左下角坐标
11 int B[N] = {3,4,3,5,};
12 int C[N] = {0,1,2,2,};
13 // 右上角坐标
14 int A[N] = {0,3,2,2,};
15 int D[N] = {3,2,3,5,};
16 // 地图上的分布结果
17 int tiles[H][W];
18 
19 ///////////////////////////SubMain//////////////////////////////////
20 int main(int argc, char *argv[])
21 {
22     memset(tiles, 0, sizeof(tiles));
23     // 影响力计算 (图 3)
24     for (int i = 0; i < N; i++)
25     {
26         tiles[C[i]][A[i]]++;
27         tiles[C[i]][B[i]]--;
28         tiles[D[i]][A[i]]--;
29         tiles[D[i]][B[i]]++;
30     }
31     // 横向累积和 (图 4, 5)
32     for (int y = 0; y < H; y++)
33     {
34         for (int x = 1; x < W; x++)
35         {
36             tiles[y][x] += tiles[y][x - 1];
37         }
38     }
39     // 纵向累积和 (图 6, 7)
40     for (int y = 1; y < H; y++)
41     {
42         for (int x = 0; x < W; x++)
43         {
44             tiles[y][x] += tiles[y - 1][x];
45         }
46     }
47 
48     cout << *max_element(tiles[0], tiles[0] + H * W) << endl;
49     system("pause");
50     return 0;
51 }
52 ///////////////////////////End Sub//////////////////////////////////
View Code

4.2 坐标离散化

  1 //http://www.hankcs.com/program/algorithm/aoj-0531-paint-color.html
  2 #include<iostream>
  3 #include<vector>
  4 #include<algorithm>
  5 #include<queue>
  6 #include <cstring>
  7 #define MAX_N 1000 + 16
  8  
  9 using namespace std;
 10  
 11 int N, H, W;
 12 int X1[MAX_N], X2[MAX_N], Y1[MAX_N], Y2[MAX_N];
 13 int fld[2 * MAX_N][2 * MAX_N], // 填充遍历用,代表坐标(i, j)处是否空白(压缩后)
 14 dx[4] = { 1, -1, 0, 0 }, dy[4] = { 0, 0, 1, -1 };
 15 
 16 // 压缩坐标,将坐标的值变成“这是第几种值”,返回一共有几种坐标
 17 int compress(int *x1, int *x2, int w)
 18 {
 19     vector<int>xs;
 20  
 21     for (int i = 0; i < N; ++i)
 22     {
 23         int tx1 = x1[i], tx2 = x2[i];
 24         if (1 <= tx1 && tx1 < w) xs.push_back(tx1);
 25         if (1 <= tx2 && tx2 < w) xs.push_back(tx2);
 26     }
 27     xs.push_back(0);
 28     xs.push_back(w);
 29     sort(xs.begin(), xs.end());
 30     xs.erase(unique(xs.begin(), xs.end()), xs.end());
 31     for (int i = 0; i < N; ++i)
 32     {
 33         x1[i] = find(xs.begin(), xs.end(), x1[i]) - xs.begin();
 34         x2[i] = find(xs.begin(), xs.end(), x2[i]) - xs.begin();
 35     }
 36     return xs.size() - 1;
 37 }
 38  
 39 int bfs()
 40 {
 41     int ans = 0;
 42     for (int i = 0; i < H; ++i)
 43     {
 44         for (int j = 0; j < W; ++j)
 45         {
 46             if (fld[i][j]) continue;
 47             ++ans;
 48             queue<pair<int, int> >que;
 49             que.push(make_pair(j, i));
 50             while (!que.empty())
 51             {
 52                 int nx = que.front().first, ny = que.front().second;
 53                 que.pop();
 54  
 55                 for (int i = 0; i < 4; ++i)
 56                 {
 57                     int tx = nx + dx[i], ty = ny + dy[i];
 58                     if (tx < 0 || W < tx || ty < 0 || H< ty || fld[ty][tx] > 0) continue;
 59                     que.push(make_pair(tx, ty));
 60                     fld[ty][tx] = 1;
 61                 }
 62             }
 63         }
 64     }
 65     return ans;
 66 }
 67  
 68 ///////////////////////////SubMain//////////////////////////////////
 69 int main(int argc, char *argv[])
 70 {
 71     while (cin >> W >> H, W | H)
 72     {
 73         cin >> N;
 74         for (int i = 0; i < N; ++i)
 75         {
 76             cin >> X1[i] >> Y1[i] >> X2[i] >> Y2[i];
 77         }
 78  
 79         memset(fld, 0, sizeof(fld));
 80  
 81         W = compress(X1, X2, W);
 82         H = compress(Y1, Y2, H);
 83  
 84         // imos-法
 85         for (int i = 0; i < N; i++)
 86         {
 87             fld[Y1[i]][X1[i]]++;
 88             fld[Y1[i]][X2[i]]--;
 89             fld[Y2[i]][X1[i]]--;
 90             fld[Y2[i]][X2[i]]++;
 91         }
 92         // 横向累积
 93         for (int i = 0; i < H; i++)
 94         {
 95             for (int j = 1; j < W; j++)
 96             {
 97                 fld[i][j] += fld[i][j - 1];
 98             }
 99         }
100         // 纵向累积
101         for (int i = 1; i < H; i++)
102         {
103             for (int j = 0; j < W; j++)
104             {
105                 fld[i][j] += fld[i - 1][j];
106             }
107         }// 累积完后,fld中非0部分表示有挡板
108         cout << bfs() << endl;
109     }
110     return 0;
111 }
112 ///////////////////////////End Sub//////////////////////////////////
View Code

4.3 博弈sg模板

 1 //f[]:可以取走的石子个数  
 2 //sg[]:0~n的SG函数值  
 3 //hash[]:mex{}  
 4 int f[N],sg[N],hash[N];       
 5 void getSG(int n)  
 6 {  
 7     int i,j;  
 8     memset(sg,0,sizeof(sg));  
 9     for(i=1;i<=n;i++)  
10     {  
11         memset(hash,0,sizeof(hash));  
12         for(j=1;f[j]<=i;j++)  
13             hash[sg[i-f[j]]]=1;  
14         for(j=0;j<=n;j++)    //求mes{}中未出现的最小的非负整数  
15         {  
16             if(hash[j]==0)  
17             {  
18                 sg[i]=j;  
19                 break;  
20             }  
21         }  
22     }  
23 }  
打表
 1 //注意 S数组要按从小到大排序 SG函数要初始化为-1 对于每个集合只需初始化1遍  
 2 //n是集合s的大小 S[i]是定义的特殊取法规则的数组  
 3 int s[110],sg[10010],n;  
 4 int SG_dfs(int x)  
 5 {  
 6     int i;  
 7     if(sg[x]!=-1)  
 8         return sg[x];  
 9     bool vis[110];  
10     memset(vis,0,sizeof(vis));  
11     for(i=0;i<n;i++)  
12     {  
13         if(x>=s[i])  
14         {  
15             SG_dfs(x-s[i]);  
16             vis[sg[x-s[i]]]=1;  
17         }  
18     }  
19     int e;  
20     for(i=0;;i++)  
21         if(!vis[i])  
22         {  
23             e=i;  
24             break;  
25         }  
26     return sg[x]=e;  
27 } 
DFS
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <set>
 5 
 6 using namespace std;
 7 
 8 const int maxn = 10005;
 9 
10 int sg[maxn];
11 
12 void SG()
13 {
14     sg[0] = 0;
15     for(int i = 2;i <= maxn; i++) {
16         set<int>s;
17         for(int j = 2;j <= 9; j++) {
18             int temp = i/j;
19             if(i%j) temp++;
20             s.insert(sg[temp]);
21         }
22         int now = 0;
23         while(s.count(now)) now++;
24         sg[i] = now;
25     }
26 }
27 /**
28     打表发现:先手1~9,19~162,325~2916必胜
29     满足前一个区间l,r->r*2+1,(r*2)*9
30 */
31 
32 
33 int main()
34 {
35     //SG();
36     //freopen("in.txt","r",stdin);
37     int n;
38     while(scanf("%d",&n) != EOF) {
39         int l = 1,r = 9;
40         int flag = 1;
41         while(1) {
42             if(l <= n && n <= r) {
43                 flag = true;
44                 break;
45             }
46             else if(n < l) {
47                 flag = false;
48                 break;
49             }
50             l = r*2+1;
51             r = r*2*9;
52         }
53         if(flag)
54             printf("Stan wins.\n");
55         else
56             printf("Ollie wins.\n");
57     }
58 
59     return 0;
60 }
View Code

 4.4 RMQ(区间极值查询)

 1 void ST(int n) {
 2     for (int i = 1; i <= n; i++)
 3         dp[i][0] = A[i];
 4     for (int j = 1; (1 << j) <= n; j++) {
 5         for (int i = 1; i + (1 << j) - 1 <= n; i++) {
 6             dp[i][j] = max(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]);
 7         }
 8     }
 9 }
10 int RMQ(int l, int r) {
11     int k = 0;
12     while ((1 << (k + 1)) <= r - l + 1) k++;
13     return max(dp[l][k], dp[r - (1 << k) + 1][k]);
14 }
View Code

 4.5 二维RMQ

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<string.h>
  4 #include<string>
  5 #include<stack>
  6 #include<set>
  7 #include<algorithm>
  8 #include<cmath>
  9 #include<vector>
 10 #include<map>
 11 
 12 
 13 #define ll __int64
 14 #define lll unsigned long long
 15 #define MAX 1000009
 16 #define eps 1e-8
 17 
 18 using namespace std;
 19 /*
 20 二维RMQ模板题
 21 同一维一样 用dp[row][col][i][j]表示(row,col)到(row+2^i,col+2^j)矩形内的最小值
 22 查询
 23 */
 24 
 25 int mapp[309][309];
 26 int dp[309][309][9][9];
 27 int flag;
 28 
 29 void RMQ_init2d(int m,int n)
 30 {
 31     for(int i=1; i<=m; i++)
 32     {
 33         for(int j = 1; j<=n; j++)
 34         {
 35             dp[i][j][0][0] = mapp[i][j];
 36         }
 37     }
 38     int t = log((double)n) / log(2.0);
 39 
 40     for(int i = 0; i<=t; i++)
 41     {
 42         for(int j = 0; j<=t; j++)
 43         {
 44             if(i==0&&j==0)
 45                 continue;
 46             for(int row = 1; row+(1<<i)-1<= m; row++)
 47             {
 48                 for(int col = 1; col+(1<<j)-1<= n; col++)
 49                 {
 50                     if(i)
 51                         dp[row][col][i][j]  = max(dp[row][col][i-1][j],dp[row+(1<<(i-1))][col][i-1][j]);
 52                     else
 53                         dp[row][col][i][j]  = max(dp[row][col][i][j-1],dp[row][col+(1<<(j-1))][i][j-1]);
 54                 }
 55             }
 56         }
 57     }
 58 }
 59 int RMQ_2d(int x1,int y1,int x2,int y2)
 60 {
 61     int k1 = log(double(x2 - x1 + 1)) / log(2.0);
 62     int k2 = log(double(y2 - y1 + 1)) / log(2.0);
 63     int m1 = dp[x1][y1][k1][k2];
 64     int m2 = dp[x2 - (1<<k1) + 1][y1][k1][k2];
 65     int m3 = dp[x1][y2 - (1<<k2) + 1][k1][k2];
 66     int m4 = dp[x2 - (1<<k1) + 1][y2 - (1<<k2) + 1 ][k1][k2];
 67     int _max = max(max(m1,m2),max(m3,m4));
 68     if(mapp[x1][y1]==_max||mapp[x1][y2]==_max||mapp[x2][y1]==_max||mapp[x2][y2]==_max)
 69         flag = 1;
 70     return _max;
 71 }
 72 
 73 int main()
 74 {
 75     int n,m,t;
 76     int x1,x2,y1,y2;
 77     while(~scanf("%d%d",&m,&n))
 78     {
 79         for(int i = 1; i<=m; i++)
 80         {
 81             for(int j = 1; j<=n; j++)
 82             {
 83                 scanf("%d",&mapp[i][j]);
 84             }
 85         } 
 86         RMQ_init2d(m,n);
 87         scanf("%d",&t);
 88         while(t--)
 89         {
 90             scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
 91            
 92             flag = 0;
 93             int _max = RMQ_2d(x1,y1,x2,y2);
 94             if(flag == 1)
 95                 printf("%d yes\n",_max);
 96             else
 97                 printf("%d no\n",_max);
 98         }
 99     }
100     return 0;
101 }
View Code

 

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;

int val[255][255];
int mm[255];
int dpmin[255][255][8][8];//最小值
int dpmax[255][255][8][8];//最大值

void initRMQ(int n,int m)
{
    for(int i = 1;i <= n;i++)
        for(int j = 1;j <= m;j++)
            dpmin[i][j][0][0] = dpmax[i][j][0][0] = val[i][j];
    for(int ii = 0; ii <= mm[n]; ii++)
        for(int jj = 0; jj <= mm[m]; jj++)
            if(ii+jj)
                for(int i = 1; i + (1<<ii) - 1 <= n; i++)
                    for(int j = 1; j + (1<<jj) - 1 <= m; j++)
                    {
                        if(ii)
                        {
                            dpmin[i][j][ii][jj] = min(dpmin[i][j][ii-1][jj],dpmin[i+(1<<(ii-1))][j][ii-1][jj]);
                            dpmax[i][j][ii][jj] = max(dpmax[i][j][ii-1][jj],dpmax[i+(1<<(ii-1))][j][ii-1][jj]);
                        }
                        else
                        {
                            dpmin[i][j][ii][jj] = min(dpmin[i][j][ii][jj-1],dpmin[i][j+(1<<(jj-1))][ii][jj-1]);
                            dpmax[i][j][ii][jj] = max(dpmax[i][j][ii][jj-1],dpmax[i][j+(1<<(jj-1))][ii][jj-1]);
                        }
                    }
}
//查询矩形的最大值
int rmq1(int x1,int y1,int x2,int y2)
{
    int k1 = mm[x2-x1+1];
    int k2 = mm[y2-y1+1];
    x2 = x2 - (1<<k1) + 1;
    y2 = y2 - (1<<k2) + 1;
    return max(max(dpmax[x1][y1][k1][k2],dpmax[x1][y2][k1][k2]),max(dpmax[x2][y1][k1][k2],dpmax[x2][y2][k1][k2]));
}
//查询矩形的最小值
int rmq2(int x1,int y1,int x2,int y2)
{
    int k1 = mm[x2-x1+1];
    int k2 = mm[y2-y1+1];
    x2 = x2 - (1<<k1) + 1;
    y2 = y2 - (1<<k2) + 1;
    return min(min(dpmin[x1][y1][k1][k2],dpmin[x1][y2][k1][k2]),min(dpmin[x2][y1][k1][k2],dpmin[x2][y2][k1][k2]));
}


int main()
{
    mm[0] = -1;
    for(int i = 1;i <= 500;i++)
        mm[i] = ((i&(i-1))==0)?mm[i-1]+1:mm[i-1];
    int N,B,K;
    while(scanf("%d%d%d",&N,&B,&K)==3)
    {
        for(int i = 1;i <= N;i++)
            for(int j = 1;j <= N;j++)
                scanf("%d",&val[i][j]);
        initRMQ(N,N);
        int x,y;
        while(K--)
        {
            scanf("%d%d",&x,&y);
            printf("%d\n",rmq1(x,y,x+B-1,y+B-1)-rmq2(x,y,x+B-1,y+B-1));
        }
    }
    return 0;
}
View Code

 

 

4.6 莫队算法

 1 #include<stdio.h>
 2 #include<algorithm>
 3 #include<iostream>
 4 #include<math.h>
 5 #include<cstring>
 6 #define go(i,a,b) for(int i=a;i<=b;i++)
 7 #define mem(a,b) memset(a,b,sizeof(a))
 8 #define ll long long
 9 using namespace std;const int N=50003;
10 struct Mo{int l,r,ID;ll A,B;}q[N];ll S(ll x){return x*x;}
11 ll GCD(ll a,ll b){while(b^=a^=b^=a%=b);return a;}
12 int n,m,col[N],unit,Be[N];ll sum[N],ans;
13 bool cmp(Mo a,Mo b){return Be[a.l]==Be[b.l]?a.r<b.r:a.l<b.l;}
14 bool CMP(Mo a,Mo b){return a.ID<b.ID;};
15 void revise(int x,int add){ans-=S(sum[col[x]]),sum[col[x]]+=add,ans+=S(sum[col[x]]);}
16 int main()
17 {
18     scanf("%d%d",&n,&m);unit=sqrt(n);
19     go(i,1,n)scanf("%d",&col[i]),Be[i]=i/unit+1;;
20     go(i,1,m)scanf("%d%d",&q[i].l,&q[i].r),q[i].ID=i;
21 
22     sort(q+1,q+m+1,cmp);
23 
24     int l=1,r=0;
25     go(i,1,m)
26     {
27         while(l<q[i].l)revise(l,-1),l++;
28         while(l>q[i].l)revise(l-1,1),l--;
29         while(r<q[i].r)revise(r+1,1),r++;
30         while(r>q[i].r)revise(r,-1),r--;
31 
32         if(q[i].l==q[i].r){q[i].A=0;q[i].B=1;continue;}
33         q[i].A=ans-(q[i].r-q[i].l+1);
34         q[i].B=1LL*(q[i].r-q[i].l+1)*(q[i].r-q[i].l);
35         ll gcd=GCD(q[i].A,q[i].B);q[i].A/=gcd;q[i].B/=gcd;
36     }
37 
38     sort(q+1,q+m+1,CMP);
39     go(i,1,m)printf("%lld/%lld\n",q[i].A,q[i].B);
40     return 0;
41 }//Paul_Guderian
View Code

带修莫队

 1 #include<stdio.h>
 2 #include<algorithm>
 3 #include<math.h>
 4 #define go(i,a,b) for(int i=a;i<=b;i++)
 5 using namespace std;const int N=10003;
 6 struct Query{int l,r,Tim,ID;}q[N];
 7 struct Change{int pos,New,Old;}c[N];
 8 int n,m,s[N],color[N*100],t,Time,now[N],unit,Be[N],ans[N],Ans,l=1,r,T;
 9 bool cmp(Query a,Query b)
10 {
11     return Be[a.l]==Be[b.l]?(Be[a.r]==Be[b.r]?a.Tim<b.Tim:a.r<b.r):a.l<b.l;
12 }
13 void revise(int x,int d){color[x]+=d;if(d>0)Ans+=color[x]==1;if(d<0)Ans-=color[x]==0;}
14 void going(int x,int d){if(l<=x&&x<=r)revise(d,1),revise(s[x],-1);s[x]=d;}
15 int main(){
16     scanf("%d%d",&n,&m);unit=pow(n,0.666666);
17     go(i,1,n)scanf("%d",&s[i]),now[i]=s[i],Be[i]=i/unit+1;
18     go(i,1,m){char sign;int x,y;scanf(" %c %d%d",&sign,&x,&y);
19         if(sign=='Q')q[++t]=(Query){x,y,Time,t};
20         if(sign=='R')c[++Time]=(Change){x,y,now[x]},now[x]=y;
21     }
22     sort(q+1,q+t+1,cmp);go(i,1,t)
23     {
24         while(T<q[i].Tim)going(c[T+1].pos,c[T+1].New),T++;
25         while(T>q[i].Tim)going(c[T].pos,c[T].Old),T--;
26         
27         while(l<q[i].l)revise(s[l],-1),l++;
28         while(l>q[i].l)revise(s[l-1],1),l--;
29         while(r<q[i].r)revise(s[r+1],1),r++;
30         while(r>q[i].r)revise(s[r],-1),r--;
31         
32         ans[q[i].ID]=Ans;
33     }
34     go(i,1,t)printf("%d\n",ans[i]);return 0;
35 }//Paul_Guderian
View Code

树上莫队

 1 #include<stdio.h>
 2 #include<algorithm>
 3 #include<math.h>
 4 #define go(i,a,b) for(int i=a;i<=b;i++)
 5 #define ro(i,a,b) for(int i=a;i>=b;i--)
 6 #define fo(i,a,x) for(int i=a[x],v=e[i].v;i;i=e[i].next,v=e[i].v)
 7 using namespace std;const int N=50009;
 8 struct E{int v,next;}e[N*3];
 9 int k=1,head[N],unit,Be[N],m,st[N],top,fa[N][18],deep[N];
10 int n,Q,a[N],t[N],op,x,y,p,tim,u=1,v=1,T,ans[N],vis[N];
11 void ADD(int u,int v){e[k]=(E){v,head[u]};head[u]=k++;}
12 void dfs(int u){
13     
14     go(i,1,19)if((1<<i)>deep[u])break;
15     else fa[u][i]=fa[fa[u][i-1]][i-1];
16         
17     int bottom=top;
18     fo(i,head,u)if(v!=fa[u][0])
19     {
20         fa[v][0]=u;deep[v]=deep[u]+1;dfs(v);
21         if(top-bottom>=unit){m++;while(top!=bottom)Be[st[top--]]=m;}
22     }
23     st[++top]=u;
24 }
25 int LCA(int x,int y)
26 {
27     if(deep[x]<deep[y])swap(x,y);int Dis=deep[x]-deep[y];
28     go(i,0,16)if((1<<i)&Dis)x=fa[x][i];
29     if(x==y)return x;
30     ro(i,16,0)if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
31     return x==y?x:fa[x][0];
32 }
33 struct Change{int u,New,Old;}cq[N];
34 struct Query{int u,v,tim,id;bool operator <(const Query &a) const{
35     return Be[u]==Be[a.u]?(Be[v]==Be[a.v]?tim<a.tim:Be[v]<Be[a.v]):Be[u]<Be[a.u];
36 }}q[N];
37 struct Datalock{
38     struct _blo{int l,r;}b[350];
39     int n,Be[N],m,unit,num[N],sum[350];
40     void init()
41     {
42         unit=sqrt(n);m=(n-1)/unit+1;
43         go(i,1,n)Be[i]=(i-1)/unit+1;
44         go(i,1,m)b[i].l=(i-1)*unit+1,b[i].r=i*unit;
45         b[m].r=n;
46     }
47     void Add(int v){if(v<=n)sum[Be[v]]+=(++num[v])==1;}
48     void Del(int v){if(v<=n)sum[Be[v]]-=(--num[v])==0;}
49     int mex()
50     {
51         go(i,1,m)if(sum[i]!=b[i].r-b[i].l+1)
52         go(j,b[i].l,b[i].r)if(!num[j])return j;
53         return -1;
54     }
55 }Data;
56 void revise(int u,int d){if(vis[u])Data.Del(a[u]),Data.Add(d);a[u]=d;}
57 void Run(int u){if(vis[u])Data.Del(a[u]),vis[u]=0;else Data.Add(a[u]),vis[u]=1;}
58 void move(int x,int y)
59 { 
60     if(deep[x]<deep[y])swap(x,y);
61     while(deep[x]>deep[y])Run(x),x=fa[x][0];
62     while(x!=y)Run(x),Run(y),x=fa[x][0],y=fa[y][0];
63 }
64 void Mo()
65 {
66     go(i,1,p)
67     {
68         while(T<q[i].tim)T++,revise(cq[T].u,cq[T].New);
69         while(T>q[i].tim)revise(cq[T].u,cq[T].Old),T--;
70         
71         if(u!=q[i].u)move(u,q[i].u),u=q[i].u;
72         if(v!=q[i].v)move(v,q[i].v),v=q[i].v;
73         int anc=LCA(u,v);Run(anc);ans[q[i].id]=Data.mex()-1;Run(anc);
74     }
75 }
76 int main(){scanf("%d%d",&n,&Q);unit=pow(n,0.45);
77     go(i,1,n)scanf("%d",&a[i]),t[i]=++a[i];
78     go(i,2,n){int uu,vv;scanf("%d%d",&uu,&vv);ADD(uu,vv);ADD(vv,uu);}
79     dfs(1);while(top)Be[st[top--]]=m;
80     go(i,1,Q)
81     {
82         scanf("%d%d%d",&op,&x,&y);
83         if( op)p++,q[p]=(Query){x,y,tim,p};
84         if(!op)tim++,cq[tim]=(Change){x,y+1,t[x]},t[x]=y+1;
85     } 
86     Data.n=n+1;Data.init();sort(q+1,q+1+p);Mo();
87     go(i,1,p)printf("%d\n",ans[i]);
88 }//Paul_Guderian
View Code

 C(n,k)

 1 /*20180802
 2 题意:求sum(C(n,k)) 0<=i<=k;
 3 数据范围1e5.
 4 莫队算法:推出递推公式。
 5 按块排序使得顺序解题效率最优
 6 */
 7 #include<stdio.h>
 8 #include<algorithm>
 9 #include<iostream>
10 #include<math.h>
11 #include<cstring>
12 #define go(i,a,b) for(int i=a;i<=b;i++)
13 #define mem(a,b) memset(a,b,sizeof(a))
14 #define ll long long
15 using namespace std;
16 const int N=100100;
17 const int MOD=1000000007;
18 int fac[N], inv[N], res[N], in_chunk[N];
19 int cnt, mx=100010, chunk,T;
20 //每次询问
21 struct Mo{int n,k,ID;ll ans;}q[N];
22 
23 int powi(int a, int b)
24 {
25     int c = 1;
26     for (; b; b >>= 1, a = 1ll * a * a % MOD)
27         if (b & 1) c = 1ll * c * a % MOD;
28     return c;
29 }
30 int C(int a, int b)
31 {
32     return 1ll * fac[a] * inv[b] % MOD * inv[a - b] % MOD;
33 }
34 
35 int n,unit,Be[N];ll ans;
36 //按块双关键词排序,使得k在变化过程中一定比n小
37 bool cmp(Mo a,Mo b){return Be[a.k]==Be[b.k]?a.n<b.n:a.k<b.k;}
38 bool CMP(Mo a,Mo b){return a.ID<b.ID;}
39 
40 int main()
41 {
42 
43     fac[0] = 1; for (int i = 1; i <= 100010; ++ i) fac[i] = 1ll * fac[i - 1] * i % MOD;
44     inv[mx] = powi(fac[mx], MOD - 2); for (int i = mx - 1; ~i; -- i) inv[i] = 1ll * inv[i + 1] * (i + 1) % MOD;
45 
46 
47     scanf("%d",&T);unit=sqrt(100000);
48     for(int i=0;i<=100000;i++)Be[i]=i/unit+1;
49     go(i,1,T)scanf("%d%d",&q[i].n,&q[i].k),q[i].ID=i;
50 
51     sort(q+1,q+T+1,cmp);
52     int in=0,ik=0;
53     ans=1;
54     go(i,1,T)
55     {
56         while(in<q[i].n){
57             if(ik==0){
58                 in=q[i].n;
59                 ans=1;
60             }
61             else {
62                 ans=(2*ans-C(in,ik)+MOD)%MOD;
63                 in++;
64             }
65         }
66         while(in>q[i].n){
67             if(ik==0){
68                 in=q[i].n;
69                 ans=1;
70             }
71             else {
72                 ans=(ans+C(in-1,ik))%MOD*inv[2]%MOD;
73                 in--;
74             }
75         }
76         while(ik<q[i].k){
77             ans=(ans+C(in,ik+1))%MOD;
78             ik++;
79         }
80         while(ik>q[i].k){
81             ans=(ans-C(in,ik)+MOD)%MOD;
82             ik--;
83         }
84         q[i].ans=ans;
85     }
86     sort(q+1,q+T+1,CMP);
87     go(i,1,T)printf("%lld\n",q[i].ans);
88     return 0;
89 }//Paul_Guderian
View Code

 区间覆盖问题

 1 #include<iostream>
 2 #include<stdio.h>
 3 #include<algorithm>
 4 using namespace std;
 5 
 6 
 7 int main()
 8 {
 9     int T, n, s[250001], t[250001];
10     int m;
11     double sum=0;
12         cin >> n>>m;
13         for (int i = 1; i <= n; i++){
14                 scanf("%d%d", &s[i], &t[i]);
15                 sum+=t[i]-s[i]+1;
16         }
17         sort(s + 1, s + n + 1);
18         sort(t + 1, t + n + 1);
19         int ans = 0;
20         for (int i = 1, j = 1; i <= n;)
21         {
22             if (s[i] <= t[j])
23             {
24                 if (ans < i - j)ans = i - j;
25                 i++;
26             }
27             else j++;
28         }
29         cout << ans + 1 << endl;
30         printf("%.20lf\n",sum/m);
31 
32     return 0;
33 }
View Code

 

 

五.图论

5.1 并查集

 1 //https://blog.csdn.net/u013486414/article/details/38682057
 2 const int MAXSIZE = 500;
 3 
 4 int uset[MAXSIZE];
 5 
 6 int rank[MAXSIZE];
 7 
 8  
 9 
10 void makeSet(int size) {
11 
12     for(int i = 0;i < size;i++)  uset[i] = i;
13 
14     for(int i = 0;i < size;i++)  rank[i] = 0;
15 
16 }
17 
18 int find(int x) {
19 
20     if (x != uset[x]) uset[x] = find(uset[x]);
21 
22     return uset[x];
23 
24 }
25 
26 void unionSet(int x, int y) {
27 
28     if ((x = find(x)) == (y = find(y))) return;
29 
30     if (rank[x] > rank[y]) uset[y] = x;
31 
32     else {
33 
34         uset[x] = y;
35 
36         if (rank[x] == rank[y]) rank[y]++;
37 
38     }
39 
40 }
View Code

5.2 求图中任意两点的最短距离的 弗洛伊德算法 

 1 //https://blog.csdn.net/qq_16657927/article/details/79942140
 2 /* 
 3     |Floyd算法| 
 4     |任意点对最短路算法| 
 5     |求图中任意两点的最短距离的算法| 
 6 */  
 7   
 8 for (int k = 0; k < n; k++) {    
 9     for (int i = 0; i < n; i++) {    
10         for (int j = 0; j < n; j++) {    
11             dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);    
12         }    
13     }  
14 }  
View Code

5.3 最小生成树·Kruskal

 1 //https://blog.csdn.net/qq_16657927/article/details/79942140
 2 /* 
 3     |Kruskal算法| 
 4     |适用于 稀疏图 求最小生成树| 
 5     |16/11/05ztx thanks to wangqiqi| 
 6 */  
 7   
 8 /* 
 9     第一步:点、边、加入vector,把所有边按从小到大排序 
10     第二步:并查集部分 + 下面的code 
11 */  
12   
13 void Kruskal() {      
14     ans = 0;      
15     for (int i = 0; i<len; i++) {      
16         if (Find(edge[i].a) != Find(edge[i].b)) {      
17             Union(edge[i].a, edge[i].b);      
18             ans += edge[i].len;      
19         }      
20     }      
21 }     
View Code

5.4 最小生成树· prim算法

 1 //https://blog.csdn.net/qq_16657927/article/details/79942140
 2 /*
 3     |Prim算法|
 4     |适用于 稠密图 求最小生成树|
 5     |堆优化版,时间复杂度:O(elgn)|
 6     |16/11/05ztx, thanks to chaixiaojun|
 7 */
 8 
 9 struct node {  
10     int v, len;  
11     node(int v = 0, int len = 0) :v(v), len(len) {}  
12     bool operator < (const node &a)const {  // 加入队列的元素自动按距离从小到大排序  
13         return len> a.len;  
14     }  
15 };
16 
17 vector<node> G[maxn];
18 int vis[maxn];
19 int dis[maxn];
20 
21 void init() {  
22     for (int i = 0; i<maxn; i++) {  
23         G[i].clear();  
24         dis[i] = INF;  
25         vis[i] = false;  
26     }  
27 }  
28 int Prim(int s) {  
29     priority_queue<node>Q; // 定义优先队列  
30     int ans = 0;  
31     Q.push(node(s,0));  // 起点加入队列  
32     while (!Q.empty()) {   
33         node now = Q.top(); Q.pop();  // 取出距离最小的点  
34         int v = now.v;  
35         if (vis[v]) continue;  // 同一个节点,可能会推入2次或2次以上队列,这样第一个被标记后,剩下的需要直接跳过。  
36         vis[v] = true;  // 标记一下  
37         ans += now.len;  
38         for (int i = 0; i<G[v].size(); i++) {  // 开始更新  
39             int v2 = G[v][i].v;  
40             int len = G[v][i].len;  
41             if (!vis[v2] && dis[v2] > len) {   
42                 dis[v2] = len;  
43                 Q.push(node(v2, dis[v2]));  // 更新的点加入队列并排序  
44             }  
45         }  
46     }  
47     return ans; 
48 }  
View Code
  1 //https://blog.csdn.net/qq_16657927/article/details/79942140
  2 #include<iostream>
  3 #include<string>
  4 #include<vector>
  5 using  namespace std;
  6 
  7 //首先是使用邻接矩阵完成Prim算法
  8 struct Graph {
  9     int vexnum;  //顶点个数
 10     int edge;   //边的条数
 11     int ** arc; //邻接矩阵
 12     string *information; //记录每个顶点名称
 13 };
 14 
 15 //创建图
 16 void createGraph(Graph & g) {
 17     cout << "请输入顶点数:输入边的条数" << endl;
 18     cin >> g.vexnum;
 19     cin >> g.edge;  //输入边的条数
 20 
 21     g.information = new string[g.vexnum];
 22     g.arc = new int*[g.vexnum];
 23     int i = 0;
 24 
 25     //开辟空间的同时,进行名称的初始化
 26     for (i = 0; i < g.vexnum; i++) {
 27         g.arc[i] = new int[g.vexnum];
 28         g.information[i]="v"+ std::to_string(i+1);//对每个顶点进行命名
 29         for (int k = 0; k < g.vexnum; k++) {
 30             g.arc[i][k] = INT_MAX;          //初始化我们的邻接矩阵
 31         }
 32     }
 33 
 34     cout << "请输入每条边之间的顶点编号(顶点编号从1开始),以及该边的权重:" << endl;
 35     for (i = 0; i < g.edge; i++) {
 36         int start;
 37         int end;
 38         cin >> start;   //输入每条边的起点
 39         cin >> end;     //输入每条边的终点
 40         int weight;
 41         cin >> weight;
 42         g.arc[start-1][end-1]=weight;//无向图的边是相反的
 43         g.arc[end-1][start-1] = weight;
 44     }
 45 }
 46 
 47 //打印图
 48 void print(Graph g) {
 49     int i;
 50     for (i = 0; i < g.vexnum; i++) {
 51         //cout << g.information[i] << " ";
 52         for (int j = 0; j < g.vexnum; j++) {
 53             if (g.arc[i][j] == INT_MAX)
 54                 cout << "" << " ";
 55             else
 56             cout << g.arc[i][j] << " ";
 57         }
 58         cout << endl;
 59     }
 60 }
 61 
 62 //作为记录边的信息,这些边都是达到end的所有边中,权重最小的那个
 63 struct Assis_array {
 64     int start; //边的终点
 65     int end;  //边的起点
 66     int weight;  //边的权重
 67 };
 68 //进行prim算法实现,使用的邻接矩阵的方法实现。
 69 void Prim(Graph g,int begin) {
 70 
 71     //close_edge这个数组记录到达某个顶点的各个边中的权重最大的那个边
 72     Assis_array *close_edge=new Assis_array[g.vexnum];
 73 
 74     int j;
 75 
 76     //进行close_edge的初始化,更加开始起点进行初始化
 77     for (j = 0; j < g.vexnum; j++) {
 78         if (j != begin - 1) {
 79             close_edge[j].start = begin-1;
 80             close_edge[j].end = j;
 81             close_edge[j].weight = g.arc[begin - 1][j];
 82         }
 83     }
 84     //把起点的close_edge中的值设置为-1,代表已经加入到集合U了
 85     close_edge[begin - 1].weight = -1;
 86     //访问剩下的顶点,并加入依次加入到集合U
 87     for (j = 1; j < g.vexnum; j++) {
 88 
 89         int min = INT_MAX;
 90         int k;
 91         int index;
 92         //寻找数组close_edge中权重最小的那个边
 93         for (k = 0; k < g.vexnum; k++) {
 94             if (close_edge[k].weight != -1) {  
 95                 if (close_edge[k].weight < min) {
 96                     min = close_edge[k].weight;
 97                     index = k;
 98                 }
 99             }
100         }
101         //将权重最小的那条边的终点也加入到集合U
102         close_edge[index].weight = -1;
103         //输出对应的边的信息
104         cout << g.information[close_edge[index].start] 
105             << "-----" 
106             << g.information[close_edge[index].end]
107             << "="
108             <<g.arc[close_edge[index].start][close_edge[index].end]
109             <<endl;
110 
111         //更新我们的close_edge数组。
112         for (k = 0; k < g.vexnum; k++) {
113             if (g.arc[close_edge[index].end][k] <close_edge[k].weight) {
114                 close_edge[k].weight = g.arc[close_edge[index].end][k];
115                 close_edge[k].start = close_edge[index].end;
116                 close_edge[k].end = k;
117             }
118         }
119     }
120 }
121 
122 
123 
124 int main()
125 {
126     Graph g;
127     createGraph(g);//基本都是无向网图,所以我们只实现了无向网图
128     print(g);
129     Prim(g, 1);
130     system("pause");
131     return 0;
132 }
View Code

5.5 染色法

 1 /* 
 2     |交叉染色法判断二分图| 
 3     |16/11/05ztx| 
 4 */  
 5   
 6 int bipartite(int s) {    
 7     int u, v;    
 8     queue<int>Q;    
 9     color[s] = 1;    
10     Q.push(s);    
11     while (!Q.empty()) {    
12         u = Q.front();    
13         Q.pop();    
14         for (int i = 0; i < G[u].size(); i++) {    
15             v = G[u][i];    
16             if (color[v] == 0) {    
17                 color[v] = -color[u];    
18                 Q.push(v);    
19             }    
20             else if (color[v] == color[u])    
21                 return 0;    
22         }    
23     }    
24     return 1;    
25 }    
View Code

5.6 匈牙利算法

 1 //https://blog.csdn.net/qq_16657927/article/details/79942140
 2 /* 
 3     |求解最大匹配问题| 
 4     |递归实现| 
 5     |16/11/05ztx| 
 6 */  
 7   
 8 vector<int>G[maxn];    
 9 bool inpath[maxn];  //  标记    
10 int match[maxn];    //  记录匹配对象    
11 void init()    
12 {    
13     memset(match, -1, sizeof(match));    
14     for (int i = 0; i < maxn; ++i) {    
15         G[i].clear();    
16     }    
17 }    
18 bool findpath(int k) {    
19     for (int i = 0; i < G[k].size(); ++i) {    
20         int v = G[k][i];    
21         if (!inpath[v]) {    
22             inpath[v] = true;    
23             if (match[v] == -1 || findpath(match[v])) { // 递归    
24                 match[v] = k; // 即匹配对象是“k妹子”的    
25                 return true;    
26             }    
27         }    
28     }    
29     return false;    
30 }    
31   
32 void hungary() {    
33     int cnt = 0;    
34     for (int i = 1; i <= m; i++) {  // m为需要匹配的“妹子”数    
35         memset(inpath, false, sizeof(inpath)); // 每次都要初始化    
36         if (findpath(i)) cnt++;    
37     }    
38     cout << cnt << endl;    
39 }    
View Code
 1 /* 
 2     |求解最大匹配问题| 
 3     |dfs实现| 
 4     |16/11/05ztx| 
 5 */  
 6   
 7 int v1, v2;    
 8 bool Map[501][501];    
 9 bool visit[501];    
10 int link[501];    
11 int result;    
12   
13 bool dfs(int x)  {    
14     for (int y = 1; y <= v2; ++y)  {    
15         if (Map[x][y] && !visit[y])  {    
16             visit[y] = true;    
17             if (link[y] == 0 || dfs(link[y]))  {    
18                 link[y] = x;    
19                 return true;    
20             } } }    
21     return false;    
22 }    
23   
24   
25 void Search()  {    
26     for (int x = 1; x <= v1; x++)  {    
27         memset(visit,false,sizeof(visit));    
28         if (dfs(x))    
29             result++;    
30     }  
31 }  
View Code

 5.7 Dijstra算法

 1 //https://blog.csdn.net/mengxiang000000/article/details/50421243
 2 #include<stdio.h>
 3 #include<string.h>
 4 #include<iostream>
 5 using namespace std;
 6 #define N 0x1f1f1f1f
 7 int w[151][151];
 8 int d[155];
 9 int ans,vis[151];
10 int n,m;
11 void Dij()
12 {
13     int i,j,k,v,tmp;
14     memset(vis,0,sizeof(vis));
15     for(i=1;i<=n;i++)
16         d[i]=w[1][i];
17     d[1]=0;
18     vis[1]=1;
19     for(i=1;i<=n;i++)
20     {
21         tmp=N;
22         for(j=1;j<=n;j++)
23         {
24             if(tmp>d[j]&&!vis[j])
25             {
26                 tmp=d[j];
27                 v=j;
28             }
29         }
30         vis[v]=1;
31         for(k=1;k<=n;k++)
32         {
33             if(!vis[k])
34             d[k]=min(d[k],d[v]+w[v][k]);
35         }
36     }
37 }
38 int main()
39 {
40     while(~scanf("%d%d",&n,&m))
41     {
42         if(n==0&&m==0)break;
43         for(int i=1;i<=n;i++)
44         {
45             for(int j=1;j<=n;j++)
46             {
47                 w[i][j]=0x1f1f1f1f;
48             }
49         }
50         for(int i=0;i<m;i++)
51         {
52             int a,b,dis;
53             scanf("%d%d%d",&a,&b,&dis);
54             if(w[a][b]>dis)
55             w[a][b]=w[b][a]=dis;
56         }
57         Dij();
58         printf("%d\n",d[n]);
59     }
60 }
View Code

 5.8 Bellman-ford算法

 1 struct edge{int from,to,cost;};
 2 
 3 edge es[MAX_E];
 4 
 5 int d[MAX_V];
 6 int V,E;
 7 
 8 void shortest(int k){
 9     memset(d,0x3f,sizeof(d));
10     d[k]=0;
11     while(true){
12         bool update=false;
13         for(int i=0;i<E;i++){
14             edge e=es[i];
15             if(d[e.from]!=INF&&d[e.from]+e.cost<d[e.to]){
16                 d[e.to]=d[e.from]+e.cost;
17                 update=true;
18             }
19         }
20         if(!update)break;
21     }
22 }
View Code

 

5.11 拓扑排序

 1 #include <iostream>
 2 #include <iostream>
 3 #include <cstdio>
 4 #include <algorithm>
 5 #include <cstring>
 6 #include <sstream>
 7 #include <set>
 8 #include <map>
 9 #include <queue>
10 #include <stack>
11 #include <cmath>
12 #define nmax 200
13 #define MEM(x) memset(x,0,sizeof(x))
14 using namespace std;
15 vector<int> v[nmax];
16 int indegree[nmax];
17 int n;
18 bool suc = true;
19 queue<int> ans;
20 void topsort()
21 {
22     queue<int> q;
23     while(1){
24         for(int i = 1; i<=n ;++i){
25             if(indegree[i] == 0){
26                 q.push(i);
27                 ans.push(i);
28                 indegree[i] = -1;
29             }
30         }
31         if(q.empty()) break;
32         while(!q.empty()){
33             int t = q.front(); q.pop();
34             for(int j = 0;j<v[t].size();++j){
35                 int tt = v[t][j];
36                 if(indegree[tt] == -1){
37                     suc = false;
38                     break;
39                 }else indegree[tt]--;
40             }
41             v[t].clear();
42             if(!suc) break;
43         }
44         if(!suc) break;
45     }
46     if(ans.size() <n){
47         suc =false;
48         return;
49     }
50 }
51 void output()
52 {
53     bool isfirst = true;
54     while(!ans.empty()){
55         int t = ans.front(); ans.pop();
56         if(isfirst){
57             printf("%d",t);
58             isfirst = false;
59         }else
60             printf(" %d",t);
61     }
62     printf("\n");
63 }
64 int main()
65 {
66     //freopen("in.txt","r",stdin);
67     int m;
68     while(scanf("%d%d",&n,&m) ==2 && (n||m)){
69         MEM(indegree);
70         suc = true;
71         int a,b;
72         for(int i = 0; i<m; ++i){
73             scanf("%d%d",&a,&b);
74             indegree[b]++;
75             v[a].push_back(b);
76         }
77         topsort();
78         if(suc) output();
79         else printf("failed\n");
80     }
81     return 0;
82 }
View Code

 5.12 数字游戏dfs记录路径

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 
 5 using namespace std;
 6 
 7 typedef long long LL;
 8 
 9 bool flag;
10 LL a, b;
11 int tp;
12 LL link[1014];
13 
14 void dfs(LL x);
15 
16 int main(){
17     while(~scanf("%lld %lld", &a, &b)){
18         tp = 0, flag = false;
19         link[tp++] = a;
20         dfs(a);
21         if(flag) {
22             printf("YES\n");
23             for(int i = 0; i < tp; i++)
24                 printf("%lld%c", link[i], i == tp-1? '\n': ' ');
25         }
26         else {
27             printf("NO\n");
28         }
29     }
30     return 0;
31 }
32 void dfs(LL x){
33     if(flag || x > b) return;
34 
35     link[tp++] = x<<1;
36     if(link[tp-1] == b){
37         flag = true;
38         return;
39     }
40     dfs(link[tp-1]);
41     if(flag) return;
42     else tp--;
43 
44     link[tp++] = x*(LL)10 + (LL)1;
45     if(link[tp-1] == b){
46         flag = true;
47         return;
48     }
49     dfs(link[tp-1]);
50     if(flag) return;
51     else tp--;
52 
53     return;
54 }
数字游戏dfs记录路径

 5.13 最长路径

// A C++ program to find single source longest distances in a DAG
#include <iostream>
#include <list>
#include <stack>
#include <limits.h>
#define NINF INT_MIN
using namespace std;

//图通过邻接表来描述。邻接表中的每个顶点包含所连接的顶点的数据,以及边的权值。
class AdjListNode
{
    int v;
    int weight;
public:
    AdjListNode(int _v, int _w)  { v = _v;  weight = _w;}
    int getV()       {  return v;  }
    int getWeight()  {  return weight; }
};

// Class to represent a graph using adjacency list representation
class Graph
{
    int V;    // No. of vertices’

    // Pointer to an array containing adjacency lists
    list<AdjListNode> *adj;

    // A function used by longestPath
    void topologicalSortUtil(int v, bool visited[], stack<int> &Stack);
public:
    Graph(int V);   // Constructor

    // function to add an edge to graph
    void addEdge(int u, int v, int weight);

    // Finds longest distances from given source vertex
    void longestPath(int s);
};

Graph::Graph(int V) // Constructor
{
    this->V = V;
    adj = new list<AdjListNode>[V];
}

void Graph::addEdge(int u, int v, int weight)
{
    AdjListNode node(v, weight);
    adj[u].push_back(node); // Add v to u’s list
}

// 通过递归求出拓扑序列. 详细描述,可参考下面的链接。
// http://www.geeksforgeeks.org/topological-sorting/
void Graph::topologicalSortUtil(int v, bool visited[], stack<int> &Stack)
{
    // 标记当前顶点为已访问
    visited[v] = true;

    // 对所有邻接点执行递归调用
    list<AdjListNode>::iterator i;
    for (i = adj[v].begin(); i != adj[v].end(); ++i)
    {
        AdjListNode node = *i;
        if (!visited[node.getV()])
            topologicalSortUtil(node.getV(), visited, Stack);
    }

    // 当某个点没有邻接点时,递归结束,将该点存入栈中。
    Stack.push(v);
}

// 根据传入的顶点,求出到到其它点的最长路径. longestPath使用了
// topologicalSortUtil() 方法获得顶点的拓扑序。
void Graph::longestPath(int s)
{
    stack<int> Stack;
    int dist[V];

    // 标记所有的顶点为未访问
    bool *visited = new bool[V];
    for (int i = 0; i < V; i++)
        visited[i] = false;

    // 对每个顶点调用topologicalSortUtil,最终求出图的拓扑序列存入到Stack中。
    for (int i = 0; i < V; i++)
        if (visited[i] == false)
            topologicalSortUtil(i, visited, Stack);

    //初始化到所有顶点的距离为负无穷
    //到源点的距离为0
    for (int i = 0; i < V; i++)
        dist[i] = NINF;
    dist[s] = 0;

    // 处理拓扑序列中的点
    while (Stack.empty() == false)
    {
        //取出拓扑序列中的第一个点
        int u = Stack.top();
        Stack.pop();

        // 更新到所有邻接点的距离
        list<AdjListNode>::iterator i;
        if (dist[u] != NINF)
        {
          for (i = adj[u].begin(); i != adj[u].end(); ++i)
             if (dist[i->getV()] < dist[u] + i->getWeight())
                dist[i->getV()] = dist[u] + i->getWeight();
        }
    }

    // 打印最长路径
    for (int i = 0; i < V; i++)
        (dist[i] == NINF)? cout << "INF ": cout << dist[i] << " ";
}
// Driver program to test above functions
int main()
{
    // Create a graph given in the above diagram.  Here vertex numbers are
    // 0, 1, 2, 3, 4, 5 with following mappings:
    // 0=r, 1=s, 2=t, 3=x, 4=y, 5=z
    Graph g(6);
    g.addEdge(0, 1, 5);
    g.addEdge(0, 2, 3);
    g.addEdge(1, 3, 6);
    g.addEdge(1, 2, 2);
    g.addEdge(2, 4, 4);
    g.addEdge(2, 5, 2);
    g.addEdge(2, 3, 7);
    g.addEdge(3, 5, 1);
    g.addEdge(3, 4, -1);
    g.addEdge(4, 5, -2);

    int s = 1;
    cout << "Following are longest distances from source vertex " << s <<" \n";
    g.longestPath(s);

    return 0;
}
最长路径

 

六.数据结构

6.1 滑动区间最大值

 1 #include<cstdio>
 2 const int N=10000010;
 3 int T,n,m,k,P,Q,R,MOD,i,a[N],q[N],h,t;long long A,B;
 4 int main(){
 5   scanf("%d",&T);
 6   while(T--){
 7     scanf("%d%d%d%d%d%d%d",&n,&m,&k,&P,&Q,&R,&MOD);
 8     for(i=1;i<=k;i++)scanf("%d",&a[i]);
 9     for(i=k+1;i<=n;i++)a[i]=(1LL*P*a[i-1]+1LL*Q*i+R)%MOD;
10     for(h=1,t=A=B=0,i=n;i;i--){
11       while(h<=t&&a[q[t]]<=a[i])t--;
12       q[++t]=i;
13       if(i+m-1<=n){
14         while(q[h]>=i+m)h++;
15         A+=i^a[q[h]];
16         B+=i^(t-h+1);
17       }
18     }
19     printf("%lld %lld\n",A,B);
20   }
21 }
View Code

6.2 树状数组

 1 int lowbit(int i)
 2 {
 3     return i & -i;//求数组下标数的二进制的非0最低位所表示的值
 4 }
 5 void update(int i,int val)//更新单节点的值
 6 {
 7     while(i<=n){
 8         a[i]+=val;
 9         i+=lowbit(i);//由叶子节点向上更新a数组
10     }
11 }
12 int sum(int i)//求和节点的值
13 {
14     int ret=0;
15     while(i>0){
16         ret+=a[i];//从右往左区间求和
17         i-=lowbit(i);
18     }
19     return ret;
20 }
View Code
 1     #include <iostream>
 2     #include <cstdio>
 3     #include <algorithm>
 4     #include <cmath>
 5     #include <cstring>
 6     using namespace std;
 7     int n,m,tree[2000010];
 8     int lowbit(int k)
 9     {
10         return k & -k;
11     }
12     void add(int x,int k)
13     {
14         while(x<=n)
15         {
16             tree[x]+=k;
17             x+=lowbit(x);
18         }
19     }
20     int sum(int x)
21     {
22         int ans=0;
23         while(x!=0)
24         {
25             ans+=tree[x];
26             x-=lowbit(x);
27         }
28         return ans;
29     }
30     int main()
31     {
32         cin>>n>>m;
33         for(int i=1;i<=n;i++)
34         {
35             int a;
36             scanf("%d",&a);
37             add(i,a);
38         }
39         for(int i=1;i<=m;i++)
40         {
41             int a,b,c;
42             scanf("%d%d%d",&a,&b,&c);
43             if(a==1)
44                 add(b,c);
45             if(a==2)
46                 cout<<sum(c)-sum(b-1)<<endl;
47         }
48     }
点修改求区间
 1     #include <iostream>
 2     #include <algorithm>
 3     #include <cstdio>
 4     #include <cstring>
 5     #include <cmath>
 6     #include <queue>
 7     using namespace std;
 8     int n,m;
 9     int input[500010];
10     int tree[500100];
11     int lowbit(int x)
12     {
13         return x & -x;
14     }
15     void add(int x,int k)
16     {
17         while(x<=n)
18         {
19             tree[x]+=k;
20             x+=lowbit(x);
21         }
22     }
23     int search(int x)
24     {
25         int ans=0;
26         while(x!=0)
27         {
28             ans+=tree[x];
29             x-=lowbit(x);
30         }
31         return ans;
32     }
33     int main()
34     {
35         cin>>n>>m;
36         for(int i=1;i<=n;i++)
37             cin>>input[i];
38         for(int i=1;i<=m;i++)
39         {
40             int a;
41             scanf("%d",&a);
42             if(a==1)
43             {
44                 int x,y,z;
45                 scanf("%d%d%d",&x,&y,&z);
46                 add(x,z);
47                 add(y+1,-z);
48             }
49             if(a==2)
50             {
51                 int x;
52                 scanf("%d",&x);
53                 printf("%d\n",input[x]+search(x));
54             }
55         }
56     }
区间修改求点

 

 

6.3 划分树 区间第k大(小)

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 using namespace std;
 6 #define MAX_SIZE 100005
 7 int sorted[MAX_SIZE];//已经排好序的数据
 8 int toleft[25][MAX_SIZE];
 9 int tree[25][MAX_SIZE];
10 void build_tree(int left, int right, int deep)
11 {
12     int i;
13     if (left == right) return ;
14     int mid = (left + right) >> 1;
15     int same = mid - left + 1; //位于左子树的数据
16     for (i = left; i <= right; ++i) {//计算放于左子树中与中位数相等的数字个数
17         if (tree[deep][i] < sorted[mid]) {
18             --same;
19         }
20     }
21     int ls = left;
22     int rs = mid + 1;
23     for (i = left; i <= right; ++i) {
24         int flag = 0;
25         if ((tree[deep][i] < sorted[mid]) || (tree[deep][i] == sorted[mid] && same > 0)) {
26             flag = 1;
27             tree[deep + 1][ls++] = tree[deep][i];
28             if (tree[deep][i] == sorted[mid])
29                 same--;
30         } else {
31             tree[deep + 1][rs++] = tree[deep][i];
32         }
33         toleft[deep][i] = toleft[deep][i - 1]+flag;
34     }
35     build_tree(left, mid, deep + 1);
36     build_tree(mid + 1, right, deep + 1);
37 }
38 int query(int left, int right, int k, int L, int R, int deep)
39 {
40     if (left == right)
41         return tree[deep][left];
42     int mid = (L + R) >> 1;
43     int x = toleft[deep][left - 1] - toleft[deep][L - 1];//位于left左边的放于左子树中的数字个数
44     int y = toleft[deep][right] - toleft[deep][L - 1];//到right为止位于左子树的个数
45     int ry = right - L - y;//到right右边为止位于右子树的数字个数
46     int cnt = y - x;//[left,right]区间内放到左子树中的个数
47     int rx = left - L - x;//left左边放在右子树中的数字个数
48     if (cnt >= k) {
49         //printf("sss %d %d %d\n", xx++, x, y);
50         return query(L + x, L + y - 1, k, L, mid, deep + 1);
51         // 因为x不在区间内 所以没关系 所以先除去,从L+x开始,然后确定范围
52     }
53     else {
54         //printf("qqq %d %d %d\n", xx++, x, y);
55         return query(mid + rx + 1, mid + 1 + ry, k - cnt, mid + 1, R, deep + 1);
56         //同理 把不在区间内的 分到右子树的元素数目排除,确定范围
57     }
58 }
59 int main()
60 {
61     int m, n;
62     int a, b, k;
63     int i;
64     while (scanf("%d%d", &m, &n) == 2) {
65         for (i = 1; i <= m; ++i) {
66             scanf("%d", &sorted[i]);
67             tree[0][i] = sorted[i];
68         }
69         sort(sorted + 1, sorted + 1 + m);
70         build_tree(1, m, 0);
71         for (i = 0; i < n; ++i) {
72             scanf("%d%d%d", &a, &b, &k);
73             printf("%d\n", query(a, b, k, 1, m, 0));
74         }
75     }
76     return 0;
77 }
View Code

 

 

 

七.字符串

7.1 Manacher 最长回文子串

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <cmath>
 6 #include <queue>
 7 #include <map>
 8 using namespace std;
 9  
10 const int N = 200010;
11 char s[N], str[N*2];
12 int p[N*2];
13 int manacher()
14 {
15     int i;
16     for(i = 1; s[i]; i++)
17         str[i*2] = s[i], str[i*2+1] = '#';
18     str[0] = '?', str[1] = '#', str[i*2] = '\0';
19     int res = 0, k = 0, maxk = 0;
20     for(int i = 2; str[i]; i++)
21     {
22         p[i] = i < maxk ? min(maxk - i, p[2*k-i]) : 1;
23         while(str[i-p[i]] == str[i+p[i]]) p[i]++;
24         if(p[i] + i > maxk)
25             k = i, maxk = i + p[i];
26         res = max(res, p[i]);
27     }
28     return res - 1;
29 }
30  
31 int main()
32 {
33     while(~ scanf(" %s", s + 1))
34         printf("%d\n", manacher());
35  
36     return 0;
37 }
View Code

 7.2 最小/最大表示

 1 int getMin(char *s)
 2 {
 3     int i = 0, j = 1, l;
 4     int len = strlen(s);
 5     while(i < len && j < len)
 6     {
 7         for(l = 0; l < len; l++)
 8             if(s[(i + l) % len] != s[(j + l) % len]) break;
 9         if(l >= len) break;
10         if(s[(i + l) % len] > s[(j + l) % len])
11         {
12             if(i + l + 1 > j) i = i + l + 1;
13             else i = j + 1;
14         }
15         else if(j + l + 1 > i) j = j + l + 1;
16         else j = i + 1;
17     }
18     return i < j ? i : j;
19 }
20  
21 int getMax(char *s)
22 {
23     int len = strlen(s);
24     int i = 0, j = 1, k = 0;
25     while(i < len && j < len && k < len)
26     {
27         int t = s[(i+k)%len]-s[(j+k)%len];
28         if(!t) k++;
29         else
30         {
31             if(t > 0)
32             {
33                 if(j+k+1 > i) j = j+k+1;
34                 else j = i+1;
35             }
36             else if(i+k+1 > j) i = i+k+1;
37             else i = j+1;
38             k = 0;
39         }
40     }
41     return i < j ? i : j;
42 }
View Code

 7.3 后缀数组

倍增法nlogn

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int MAX_N=1000010;
 5 
 6 int n,k;
 7 int rank[MAX_N];
 8 int tmp[MAX_N];
 9 int sa[MAX_N];
10 //比较(rank[i],rank[i+k])和rank[j],rank[j+k]
11 bool compare_sa(int i,int j){
12     if(rank[i]!=rank[j])return rank[i]<rank[j];
13     else {
14         int ri=i+k<=n?rank[i+k]:-1;
15         int rj=j+k<=n?rank[j+k]:-1;
16         return ri<rj;
17     }
18 }
19 
20 //计算字符串S的后缀数组
21 void construct_sa(string S,int *sa){
22     n=S.length();
23 
24     //初始长度为1,rank直接截取字符编码
25     for(int i=0;i<=n;i++){
26         sa[i]=i;
27         rank[i]=i<n?S[i]:-1;
28     }
29 
30     //利用对长度为k的排序对长度为2k的排序
31     for(k=1;k<=n;k*=2){
32         sort(sa,sa+n+1,compare_sa);
33 
34         //先在tmp中临时存储新计算的rank,再转存回rank中
35         tmp[sa[0]]=0;
36         for(int i=1;i<=n;i++){
37             tmp[sa[i]]=tmp[sa[i-1]] + (compare_sa(sa[i-1],sa[i]) ? 1 : 0) ;
38         }
39         for(int i=0;i<=n;i++){
40             rank[i]=tmp[i];
41         }
42     }
43 }
44 
45 int main(){
46     string x;
47     cin >> x;
48     construct_sa(x,sa);
49     for(int i=1;i<=x.size();i++){
50         printf("%d ",sa[i]+1);
51     }
52     printf("\n");
53 }
View Code

加桶不知道为什么就快了很多的倍增法

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #define inv inline void
 5 #define maxN 1000010
 6 using namespace std;
 7 char s[maxN];
 8 //s是字符串的读入
 9 int a[maxN],rk[maxN],sa[maxN],tp[maxN],tax[maxN],n,m;
10 //a是暂存数组,rk(第一关键字)第i位的排名,sa是排名为i的位置,tp是第二关键字辅助用的,tax是桶数组;
11 inv read(){
12     scanf("%s",&s);
13     n=strlen(s);
14     for(int i=0;i<n;i++) a[i+1]=s[i];
15     //读入
16 }
17 inv Rsort(){
18     for(int i=0;i<=m;i++) tax[i]=0;
19     //tax是桶
20     //tax清零
21     for(int i=1;i<=n;i++) tax[rk[tp[i]]]++;
22     //每一个出现的第一关键字++
23     for(int i=1;i<=m;i++) tax[i]+=tax[i-1];
24     //tax中i现在代表这个数至多能排第几位
25     for(int i=n;i>=1;i--) sa[tax[rk[tp[i]]]--]=tp[i];
26     //如果是第一遍就先不看这个
27     //就是把这一轮的sa做出来
28     //第二轮开始因为tp是按第二关键字进数组的
29     //所以从后往前来第二关键字肯定比前面小
30     //所以第一关键字相同时,第二关键字越大排名越后
31     //所以先拿到最大的值然后--
32 }
33 inv Suffix(){
34     for(int i=1;i<=n;i++) rk[i]=a[i],tp[i]=i;
35     //因为是第一轮所以直接用ascii码和位置当关键字;
36     Rsort();
37 //  for(int i=1;i<=n;i++) printf("%d ",sa[i]);
38     for(int k=1;k<=n;k<<=1){
39         int num;
40         num=0;
41         for(int i=n-k+1;i<=n;i++) tp[++num]=i;
42         //从n-k+1开始,到n的位置的第二关键字都为零,所以先入数组
43         for(int i=1;i<=n;i++) if(sa[i]>k) tp[++num]=sa[i]-k;
44         //因为sa是排好序的,当sa[i]这个位置大于k时
45         //sa[i]就会作为别人的第二关键字,因为sa排好序的所以从小往大一个for就ok
46         //所以就把sa[i]-k这个位置先进
47         //上面这两个for做完后tp就完成了
48         Rsort();
49         //再进行一次基数排序
50         swap(rk,tp);
51         //用tp存下这一轮rk
52         //下面开始更新下一轮rk
53         rk[sa[1]]=1;
54         //sa[1]的rk就是1
55         num=1;
56         //计数器&&自带更新排名
57         for(int i=2;i<=n;i++)
58           rk[sa[i]]=(tp[sa[i]]==tp[sa[i-1]]&&tp[sa[i]+k]==tp[sa[i-1]+k])?num:++num;
59           //()里面的是比较第一和第二关键字是否相同
60           //()里面的如果成立,就直接等于num
61           //如果不成立就++num并变成num++
62         if(num==n) break;
63         //如果有n种排名就done了!
64         m=num;
65         //m代表tp的种类
66     }
67     return;
68 }
69 int main(){
70     freopen("data.in","r",stdin);
71     freopen("data.out","w",stdout);
72 
73     read();
74     m=122;
75     Suffix();
76     for(int i=1;i<=n;i++) printf("%d ",sa[i]);
77 //  printf("\n");
78 //  for(int i=1;i<=n;i++) printf("%d ",rk[i]);
79 }
View Code

DC3

  1 /*
  2 suffix数组:第i位到最后的字符串
  3 sa数组:将排序后的后缀的开头位置顺次放入SA中,称为后缀数组
  4 rank数组:令rank[i]保存suffix[i]在排序中的名次,名次数组
  5 */
  6 #include "stdio.h"
  7 #include "string.h"
  8 #define maxn 20004
  9 #define maxm 1000005
 10  
 11 #define F(x) ((x)/3+((x)%3==1?0:tb))
 12 #define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2)
 13 int wa[maxn],wb[maxn],wv[maxn],ws[maxm];
 14 int c0(int *r,int a,int b)
 15 {return r[a]==r[b]&&r[a+1]==r[b+1]&&r[a+2]==r[b+2];}
 16 int c12(int k,int *r,int a,int b)
 17 {if(k==2) return r[a]<r[b]||r[a]==r[b]&&c12(1,r,a+1,b+1);
 18  else return r[a]<r[b]||r[a]==r[b]&&wv[a+1]<wv[b+1];}
 19 void sort(int *r,int *a,int *b,int n,int m)
 20 {
 21      int i;
 22      for(i=0;i<n;i++) wv[i]=r[a[i]];
 23      for(i=0;i<m;i++) ws[i]=0;
 24      for(i=0;i<n;i++) ws[wv[i]]++;
 25      for(i=1;i<m;i++) ws[i]+=ws[i-1];
 26      for(i=n-1;i>=0;i--) b[--ws[wv[i]]]=a[i];
 27      return;
 28 }
 29 void dc3(int *r,int *sa,int n,int m)
 30 {
 31      int i,j,*rn=r+n,*san=sa+n,ta=0,tb=(n+1)/3,tbc=0,p;
 32      r[n]=r[n+1]=0;
 33      for(i=0;i<n;i++) if(i%3!=0) wa[tbc++]=i;
 34      sort(r+2,wa,wb,tbc,m);
 35      sort(r+1,wb,wa,tbc,m);
 36      sort(r,wa,wb,tbc,m);
 37      for(p=1,rn[F(wb[0])]=0,i=1;i<tbc;i++)
 38      rn[F(wb[i])]=c0(r,wb[i-1],wb[i])?p-1:p++;
 39      if(p<tbc) dc3(rn,san,tbc,p);
 40      else for(i=0;i<tbc;i++) san[rn[i]]=i;
 41      for(i=0;i<tbc;i++) if(san[i]<tb) wb[ta++]=san[i]*3;
 42      if(n%3==1) wb[ta++]=n-1;
 43      sort(r,wb,wa,ta,m);
 44      for(i=0;i<tbc;i++) wv[wb[i]=G(san[i])]=i;
 45      for(i=0,j=0,p=0;i<ta && j<tbc;p++)
 46      sa[p]=c12(wb[j]%3,r,wa[i],wb[j])?wa[i++]:wb[j++];
 47      for(;i<ta;p++) sa[p]=wa[i++];
 48      for(;j<tbc;p++) sa[p]=wb[j++];
 49      return;
 50 }
 51 int rank[maxn],height[maxn];
 52 void calheight(int *r,int *sa,int n)
 53 {
 54      int i,j,k=0;
 55      for(i=1;i<=n;i++) rank[sa[i]]=i;
 56      for(i=0;i<n;height[rank[i++]]=k)
 57      for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);
 58      return;
 59 }
 60 int RMQ[maxn];
 61 int mm[maxn];
 62 int best[20][maxn];
 63 void initRMQ(int n)
 64 {
 65      int i,j,a,b;
 66      for(mm[0]=-1,i=1;i<=n;i++)
 67      mm[i]=((i&(i-1))==0)?mm[i-1]+1:mm[i-1];
 68      for(i=1;i<=n;i++) best[0][i]=i;
 69      for(i=1;i<=mm[n];i++)
 70      for(j=1;j<=n+1-(1<<i);j++)
 71      {
 72        a=best[i-1][j];
 73        b=best[i-1][j+(1<<(i-1))];
 74        if(RMQ[a]<RMQ[b]) best[i][j]=a;
 75        else best[i][j]=b;
 76      }
 77      return;
 78 }
 79 int askRMQ(int a,int b)
 80 {
 81     int t;
 82     t=mm[b-a+1];b-=(1<<t)-1;
 83     a=best[t][a];b=best[t][b];
 84     return RMQ[a]<RMQ[b]?a:b;
 85 }
 86 int lcp(int a,int b)//从头开始比较a和b的对应字符持续相等的最远值
 87 {
 88     int t;
 89     a=rank[a];b=rank[b];
 90     if(a>b) {t=a;a=b;b=t;}
 91     return(height[askRMQ(a+1,b)]);
 92 }
 93 /*
 94 */
 95 char st[maxn];
 96 int r[maxn*3],sa[maxn*3];
 97 /*求最长回文长
 98 int main()
 99 {
100     int i,n,len,k,ans=0,w;
101     scanf("%s",st);
102     len=strlen(st);
103     for(i=0;i<len;i++) r[i]=st[i];
104     r[len]=1;
105     for(i=0;i<len;i++) r[i+len+1]=st[len-1-i];
106     n=len+len+1;
107     r[n]=0;
108     dc3(r,sa,n+1,128);
109     calheight(r,sa,n);
110     for(i=1;i<=n;i++) RMQ[i]=height[i];
111     initRMQ(n);
112     for(i=0;i<len;i++)
113     {
114       k=lcp(i,n-i);
115       if(k*2>ans) ans=k*2,w=i-k;
116       k=lcp(i,n-i-1);
117       if(k*2-1>ans) ans=k*2-1,w=i-k+1;
118     }
119     st[w+ans]=0;
120     printf("%s\n",st+w);
121     return 0;
122 }*/
123 /*求最大公共字串长
124 int main()
125 {
126     int i,j,n,ans=0;
127     scanf("%s",st);
128     j=strlen(st);
129     st[j]=1;
130     scanf("%s",st+j+1);
131     n=strlen(st);
132     for(i=0;i<n;i++) r[i]=st[i];
133     r[n]=0;
134     dc3(r,sa,n+1,128);
135     calheight(r,sa,n);
136     for(i=2;i<=n;i++)
137     if(height[i]>ans)
138     if((j<sa[i-1] && j>sa[i])
139     || (j>sa[i-1] && j<sa[i])) ans=height[i];
140     printf("%d\n",ans);
141     return 0;
142 }
143 */
144 /*不可重叠最长重复子串
145  POJ 1743 最长重复子串(不可重叠)
146 题意:
147 有N(1 <= N <=20000)个音符的序列来表示一首乐曲,每个音符都是1..88范围内的整数,现在要找一个重复的主题。“主题”是整个音符序列的一个子串,它需要满足如下条件:
148 1.长度至少为5个音符
149 2.在乐曲中重复出现(可能经过转调,“转调”的意思是主题序列中每个音符都被加上或减去了同一个整数值。)
150 3.重复出现的同一主题不能有公共部分。
151 int check(int *sa,int n,int k)
152 {
153     int i,max=sa[1],min=sa[1];
154     for(i=2;i<=n;i++)
155     {
156       if(height[i]<k) max=min=sa[i];
157       else
158       {
159         if(sa[i]<min) min=sa[i];
160         if(sa[i]>max) max=sa[i];
161         if(max-min>k) return(1);
162       }
163     }
164     return(0);
165 }
166 int main()
167 {
168     int i,j=0,k,n;
169     int min,mid,max;
170     scanf("%d",&n);
171     while(n!=0)
172     {
173       n--;
174       for(i=0;i<n;i++)
175         scanf("%d",&r[i]);
176       for(i=0;i<n;i++)
177        r[i]=r[i]-r[i+1]+90;
178       r[n]=0;
179       dc3(r,sa,n+1,200);
180       calheight(r,sa,n);
181       min=1;max=n/2;
182       while(min<=max)
183       {
184         mid=(min+max)/2;
185         if(check(sa,n,mid)) min=mid+1;
186         else max=mid-1;
187       }
188       if(max>=4) printf("%d\n",max+1);
189       else printf("0\n");
190       scanf("%d",&n);
191     }
192     return 0;
193 }
194 */
195 /*
196 可重叠的 k 次最长重复子串
197 给定一个长度为n的整数序列,求其中至少出现k次的子序列长度最长为多长
198 int check(int n,int k,int mid)
199 {
200     int i,s=1;
201     for(i=1;i<=n;i++)
202     if(height[i]>=mid)
203     {
204       s++;
205       if(s>=k) return(1);
206     }
207     else s=1;
208     return(0);
209 }
210 int main()
211 {
212     int i,k,n;
213     int min,mid,max;
214     scanf("%d %d",&n,&k);
215     for(i=0;i<n;i++)
216     {
217       scanf("%d",&r[i]);
218       r[i]++;
219     }
220     r[n]=0;
221     dc3(r,sa,n+1,1000002);
222     calheight(r,sa,n);
223     min=1;max=n;
224     while(min<=max)
225     {
226       mid=(min+max)/2;
227       if(check(n,k,mid)) min=mid+1;
228       else max=mid-1;
229     }
230     printf("%d\n",max);
231     return 0;
232 }
233 */
234  
235 /*
236 不相同的连续子串的个数
237 int main()
238 {
239     int i,n,t,ans;
240     scanf("%d",&t);
241     while(t-->0)
242     {
243       scanf("%s",st);
244       n=strlen(st);
245       for(i=0;i<n;i++) r[i]=st[i];
246       r[n]=0;
247       dc3(r,sa,n+1,128);
248       calheight(r,sa,n);
249       ans=n*(n+1)/2;
250       for(i=1;i<=n;i++) ans-=height[i];
251       printf("%d\n",ans);
252     }
253     return 0;
254 }
255 */
256 /*
257 长度不小于 k 的公共子串的个数
258 int f[maxn];
259 int a[maxn],b[maxn],c;
260 long long ss,ans;
261 int main()
262 {
263     int i,k,l,n,t;
264     scanf("%d",&k);
265     while(k!=0)
266     {
267       scanf("%s",st);
268       l=strlen(st);
269       st[l]=1;
270       scanf("%s",st+l+1);
271       n=strlen(st);
272       for(i=0;i<n;i++) r[i]=st[i];
273       r[n]=0;
274       dc3(r,sa,n+1,128);
275       calheight(r,sa,n);
276       for(i=2;i<=n;i++)
277       {
278         f[i]=sa[i]<l;
279         height[i]-=k-1;
280         if(height[i]<0) height[i]=0;
281       }
282       height[n+1]=0;
283       a[0]=-1;ans=0;
284       for(t=0;t<=1;t++)
285       for(c=0,ss=0,i=2;i<=n;i++)
286       {
287         if(f[i]!=t) ans+=ss;
288         c++;
289         a[c]=height[i+1];
290         b[c]=f[i]==t;
291         ss+=(long long)a[c]*b[c];
292         while(a[c-1]>=a[c])
293         {
294           ss-=(long long)(a[c-1]-a[c])*b[c-1];
295           a[c-1]=a[c];
296           b[c-1]+=b[c];
297           c--;
298         }
299       }
300       printf("%I64d\n",ans);
301       scanf("%d",&k);
302     }
303     return 0;
304 }
305 */
306  
View Code

 7.4 KMP

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int maxn=1e6+7;
 5 int Next[maxn];
 6 //x表示模式串,Next保存以i为结尾的最长公共前缀和后缀的起始坐标
 7 void get_next(string x){
 8     int i,j;
 9     Next[0]=j=-1;
10     i=0;
11     while(i<x.length()){
12         while(j!=-1&&x[j]!=x[i])j=Next[j];
13         Next[++i]=++j;
14     }
15 }
16 //返回第一次匹配下标,x1匹配串,x2模式串
17 int kmp_id(string x1,string x2){
18     int i,j;
19     i=j=0;
20     while(i<x1.length()&&j<x2.length()){
21         while(j!=-1&&x1[i]!=x2[j]){
22             j=Next[j];
23         }
24         i++;
25         j++;
26     }
27     if(j==x2.length())
28         return i-j;
29     return -1;
30 }
31 
32 //返回匹配次数,x1匹配串,x2模式串
33 int kmp_ans(string x1,string x2){
34     int i,j;
35     i=j=0;
36     int ans=0;
37     while(i<x1.length()){
38         while(j!=-1&&x1[i]!=x2[j]){
39             j=Next[j];
40         }
41         if(j==x2.length()-1){
42             ans++;
43             j=Next[j];
44         }
45         i++;
46         j++;
47     }
48     return ans;
49 }
50 
51 
52 int main()
53 {
54     string x,y;
55     cin >> x;
56     get_next(x);
57     cin >>y;
58     cout <<  kmp_ans(y,x) << endl;
59     cout <<  kmp_id(y,x) << endl;
60 
61     return 0;
62 }
总结完毕

 

 1 void get_next()
 2 {//next数组保存了以i结尾的字符串的最长公共前缀和后缀的起始坐标
 3     int i,j;
 4     next[0] = j = -1;
 5     i = 0;
 6     while(i < l2)
 7     {
 8         while(j!=-1&&str2[j]!=str2[i])//自身和自身进行匹配
 9             j = next[j];
10         next[++i] = ++j; 
11     }
12 }
13 int kmp()
14 {
15     int i,j;
16     i = j = 0;
17     while(i < l1&&j<l2)
18     {
19         while(j!=-1&&str1[i]!=str2[j])
20         {
21             j = next[j];
22         }
23         i++;
24         j++;
25 
26     }
27     if(j == l2)
28         return i-j;//完全匹配时的开始下标,下标从0开始
29     return -1;//不存在匹配情况 
30 }
31 int kmp()
32 {
33     int i,j;
34     i = j = 0;
35     while(i < l1)//注意和返回下标的区别
36     {
37         while(j!=-1&&str1[i]!=str2[j])
38         {
39             j = next[j];
40         }
41         if(j == l2-1)
42         {
43            ans ++;
44            j = next[j];
45         }
46         i++;
47         j++;
48     }
49     return ans;//返回匹配次数 
50 }
View Code
 1 void getnext( char T[],int len)
 2 {
 3     int i = 0, j = -1;
 4     Next[0] = -1;
 5     while(i < len)
 6     {
 7         if(j == -1 || T[i] == T[j])
 8         {
 9             i++,j++;
10             Next[i] = j;
11         }
12         else
13             j = Next[j];
14     }
15 }
16  
17 void KMP(char s1[], char s2[], int len1, int len2 )//原串长度, 模式串长度
18 {
19     int i = 0, j = 0 ;
20     Next[0] = -1 ;
21     while( i < len1 && j < len2 )
22     {
23         if( j == -1 || s1[i] == s2[j])
24         {
25             i++;
26             j++;
27         }
28         else
29             j = Next[j];
30         if( j == len2)
31         {
32             if(i < len1)
33             {
34                 ans = min(ans, len1 - i);
35             }
36             j = Next[j];
37         }
38     }
39 }
View Code

7.5 字典树

 1 #include <cstring>
 2 #include <vector>
 3 #include <cstdio>
 4 using namespace std;
 5 //***********************************************************************************************
 6 const int maxnode = 4000 * 100 + 10;
 7 const int sigma_size = 26;
 8  
 9 // 字母表为全体小写字母的Trie
10 struct Trie {
11   int ch[maxnode][sigma_size];
12   int val[maxnode];
13   int sz; // 结点总数
14   void clear() { sz = 1; memset(ch[0], 0, sizeof(ch[0])); } // 初始时只有一个根结点
15   int idx(char c) { return c - 'a'; } // 字符c的编号
16  
17   // 插入字符串s,附加信息为v。注意v必须非0,因为0代表“本结点不是单词结点”
18   void insert(const char *s, int v) {
19     int u = 0, n = strlen(s);
20     for(int i = 0; i < n; i++) {
21       int c = idx(s[i]);
22       if(!ch[u][c]) { // 结点不存在
23         memset(ch[sz], 0, sizeof(ch[sz]));
24         val[sz] = 0;  // 中间结点的附加信息为0
25         ch[u][c] = sz++; // 新建结点
26       }
27       u = ch[u][c]; // 往下走
28     }
29     val[u] = v; // 字符串的最后一个字符的附加信息为v
30   }
31  
32   // 找字符串s的长度不超过len的前缀
33   bool find(const char *s, int len) {
34     int u = 0;
35     for(int i = 0; i < len; i++) {
36       if(s[i] == '\0') break;
37       int c = idx(s[i]);
38       if(!ch[u][c]) break;
39       u = ch[u][c];
40       if(val[u] != 0) return true; // 找到一个前缀
41     }
42     return false;
43   }
44 };
45  
46 //*****************************************************************************************************
47 //以下为模板测试
48 Trie trie;
49 const int maxl = 300000 + 10; // 文本串最大长度
50 const int maxw = 4000 + 10;   // 单词最大个数
51 const int maxwl = 100 + 10;   // 每个单词最大长度
52 char text[maxl], word[maxwl];
53 int main()
54 {
55     int n,m;
56     scanf("%d",&n);
57     trie.clear();
58     while(n--){
59         scanf("%s",word);
60         trie.insert(word,1);
61     }
62     scanf("%d",&m);
63     while(m--){
64         scanf("%s",text);
65         int l=strlen(text);
66         if(trie.find(text,l)) printf("\"%s\" in it\n",text);
67         else printf("\"%s\" not in it\n",text);
68     }
69     return 0;
70 }
刘汝佳

 

 1 //Code highlighting produced by Actipro CodeHighlighter //(freeware)http://www.CodeHighlighter.com/-->
 2 void createTrie(char *str)
 3 {
 4     int len = strlen(str);
 5     Trie *p = root, *q;
 6     for(int i=0; i<len; ++i)
 7     {
 8         int id = str[i]-'0';
 9         if(p->next[id] == NULL)
10         {
11             q = (Trie *)malloc(sizeof(Trie));
12             q->v = 1;    //初始v==1
13             for(int j=0; j<MAX; ++j)
14                 q->next[j] = NULL;
15             p->next[id] = q;
16             p = p->next[id];
17         }
18         else
19         {
20             p->next[id]->v++;
21             p = p->next[id];
22         }
23     }
24     p->v = -1;   //若为结尾,则将v改成-1表示
25 }
26 
27 //Code highlighting produced by Actipro CodeHighlighter //(freeware)http://www.CodeHighlighter.com/-->
28 int findTrie(char *str)
29 {
30     int len = strlen(str);
31     Trie *p = root;
32     for(int i=0; i<len; ++i)
33     {
34         int id = str[i]-'0';
35         p = p->next[id];
36         if(p == NULL)   //若为空集,表示不存以此为前缀的串
37             return 0;
38         if(p->v == -1)   //字符集中已有串是此串的前缀
39             return -1;
40     }
41     return -1;   //此串是字符集中某串的前缀
42 }
43 
44 //Code highlighting produced by Actipro CodeHighlighter //(freeware)http://www.CodeHighlighter.com/-->
45 int dealTrie(Trie* T)
46 {
47     int i;
48     if(T==NULL)
49         return 0;
50     for(i=0;i<MAX;i++)
51     {
52         if(T->next[i]!=NULL)
53             deal(T->next[i]);
54     }
55     free(T);
56     return 0;
57 }
View Code
 1 #include <cstring>
 2 #include <vector>
 3 #include <cstdio>
 4 using namespace std;
 5 //***********************************************************************************************
 6 const int maxnode = 4000 * 100 + 10;
 7 const int sigma_size = 26;
 8  
 9 // 字母表为全体小写字母的Trie
10 struct Trie {
11   int ch[maxnode][sigma_size];
12   int val[maxnode];
13   int sz; // 结点总数
14   void clear() { sz = 1; memset(ch[0], 0, sizeof(ch[0])); } // 初始时只有一个根结点
15   int idx(char c) { return c - 'a'; } // 字符c的编号
16  
17   // 插入字符串s,附加信息为v。注意v必须非0,因为0代表“本结点不是单词结点”
18   void insert(const char *s, int v) {
19     int u = 0, n = strlen(s);
20     for(int i = 0; i < n; i++) {
21       int c = idx(s[i]);
22       if(!ch[u][c]) { // 结点不存在
23         memset(ch[sz], 0, sizeof(ch[sz]));
24         val[sz] = 0;  // 中间结点的附加信息为0
25         ch[u][c] = sz++; // 新建结点
26       }
27       u = ch[u][c]; // 往下走
28     }
29     val[u] = v; // 字符串的最后一个字符的附加信息为v
30   }
31  
32   // 找字符串s的长度不超过len的前缀
33   bool find(const char *s, int len) {
34     int u = 0;
35     for(int i = 0; i < len; i++) {
36       if(s[i] == '\0') break;
37       int c = idx(s[i]);
38       if(!ch[u][c]) break;
39       u = ch[u][c];
40       if(val[u] != 0) return true; // 找到一个前缀
41     }
42     return false;
43   }
44 };
45  
46 //*****************************************************************************************************
47 //以下为模板测试
48 Trie trie;
49 const int maxl = 300000 + 10; // 文本串最大长度
50 const int maxw = 4000 + 10;   // 单词最大个数
51 const int maxwl = 100 + 10;   // 每个单词最大长度
52 char text[maxl], word[maxwl];
53 int main()
54 {
55     int n,m;
56     scanf("%d",&n);
57     trie.clear();
58     while(n--){
59         scanf("%s",word);
60         trie.insert(word,1);
61     }
62     scanf("%d",&m);
63     while(m--){
64         scanf("%s",text);
65         int l=strlen(text);
66         if(trie.find(text,l)) printf("\"%s\" in it\n",text);
67         else printf("\"%s\" not in it\n",text);
68     }
69     return 0;
70 }
View Code

 

7.6 AC自动机

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <queue>
  5 
  6 using namespace std;
  7 
  8 const int maxn=550000;
  9 
 10 struct AC_auto
 11 {
 12     //chd子节点 v表示字符长度,f表示失配指针,
 13     int chd[maxn][26],v[maxn],f[maxn],last[maxn],sz,ans;
 14     void init()
 15     {
 16         sz=1;ans=0;
 17         memset(v,0,sizeof(v));
 18         memset(f,0,sizeof(f));
 19         memset(chd[0],0,sizeof(chd[0]));
 20     }
 21     void insert(char* p)
 22     {
 23         int cur=0;
 24         int tmp=strlen(p);
 25         for(;*p;p++)
 26         {
 27             if(!chd[cur][*p-'a'])
 28             {
 29                 memset(chd[sz],0,sizeof(chd[sz]));
 30                 chd[cur][*p-'a']=sz++;
 31             }
 32             cur=chd[cur][*p-'a'];
 33         }
 34         v[cur]=tmp;
 35     }
 36     bool query(char* p)
 37     {
 38         int cur=0;
 39         for(;*p;p++)
 40         {
 41             if(!chd[cur][*p-'a']) break;
 42             cur=chd[cur][*p-'a'];
 43         }
 44         return v[cur]&&(!(*p));
 45     }
 46     int getFail()
 47     {
 48         queue<int> q;
 49         f[0]=0;
 50         for(int c=0;c<26;c++)
 51         {
 52             int u=chd[0][c];
 53             if(u)
 54             {
 55                 f[u]=0; q.push(u); last[u]=0;
 56             }
 57         }
 58         while(!q.empty())
 59         {
 60             int r=q.front(); q.pop();
 61             for(int c=0;c<26;c++)
 62             {
 63                 int u=chd[r][c];
 64                 if(!u){ chd[r][c]=chd[f[r]][c];continue;}///....
 65                 q.push(u);
 66                 int vv=f[r];
 67                 while(vv&&!chd[vv][c]) vv=f[vv];
 68                 f[u]=chd[vv][c];
 69                 last[u]=v[f[u]] ? f[u] : last[f[u]];
 70             }
 71         }
 72     }
 73     void solve(int j)
 74     {
 75         if(!j) return;
 76         if(v[j])
 77         {
 78             ans+=v[j];
 79             v[j]=0;
 80         }
 81         solve(last[j]);
 82     }
 83     //找出现单词(不计次数)
 84     void find(char* T)
 85     {
 86         int n=strlen(T),j=0;
 87         getFail();
 88         for(int i=0;i<n;i++)
 89         {
 90             //while(j&&!chd[j][*T-'a']) j=f[j];
 91             j=chd[j][T[i]-'a'];
 92             if(v[j]) solve(j);
 93             else if(last[j]) solve(last[j]);
 94         }
 95     }
 96     //替换最长匹配前缀为'*';
 97     void find1(char* T)
 98     {
 99         int n=strlen(T),j=0;
100         getFail();
101         for(int i=0; i<n; i++)
102         {
103 //            if(!(str[i]>='a'&&str[i]<='z'||str[i]>='A'&&str[i]<='Z'))continue;
104 
105 
106             j=chd[j][T[i]-'a'];
107             int temp=j;
108             while(temp!=0)
109             {
110                 if(v[temp] != 0)
111                 {
112                     for(int k=i-v[temp]+1; k<=i; k++)
113                     {
114                         //str1[k]='*';
115                     }
116                     break;
117                 }
118                 temp = f[temp];
119             }
120 
121 
122         }
123     }
124 }ac;
125 
126 int main()
127 {
128     int t,n;
129     char dic[100],str[1100000];
130     scanf("%d",&t);
131     while(t--)
132     {
133         ac.init();
134         scanf("%d",&n);
135         while(n--)
136         {
137             scanf("%s",dic);
138             ac.insert(dic);
139         }
140         scanf("%s",str);
141         ac.find(str);
142         printf("%d\n",ac.ans);
143     }
144     return 0;
145 }
+1
  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <queue>
  5  
  6 using namespace std;
  7  
  8 const int maxn=550000;
  9  
 10 struct AC_auto
 11 {
 12     int chd[maxn][26],v[maxn],f[maxn],last[maxn],sz,ans;
 13     void init()
 14     {
 15         sz=1;ans=0;
 16         memset(v,0,sizeof(v));
 17         memset(f,0,sizeof(f));
 18         memset(chd[0],0,sizeof(chd[0]));
 19     }
 20     void insert(char* p)
 21     {
 22         int cur=0;
 23         for(;*p;p++)
 24         {
 25             if(!chd[cur][*p-'a'])
 26             {
 27                 memset(chd[sz],0,sizeof(chd[sz]));
 28                 chd[cur][*p-'a']=sz++;
 29             }
 30             cur=chd[cur][*p-'a'];
 31         }
 32         v[cur]++;
 33     }
 34     bool query(char* p)
 35     {
 36         int cur=0;
 37         for(;*p;p++)
 38         {
 39             if(!chd[cur][*p-'a']) break;
 40             cur=chd[cur][*p-'a'];
 41         }
 42         return v[cur]&&(!(*p));
 43     }
 44     int getFail()
 45     {
 46         queue<int> q;
 47         f[0]=0;
 48         for(int c=0;c<26;c++)
 49         {
 50             int u=chd[0][c];
 51             if(u)
 52             {
 53                 f[u]=0; q.push(u); last[u]=0;
 54             }
 55         }
 56         while(!q.empty())
 57         {
 58             int r=q.front(); q.pop();
 59             for(int c=0;c<26;c++)
 60             {
 61                 int u=chd[r][c];
 62                 if(!u){ chd[r][c]=chd[f[r]][c];continue;}///....
 63                 q.push(u);
 64                 int vv=f[r];
 65                 while(vv&&!chd[vv][c]) vv=f[vv];
 66                 f[u]=chd[vv][c];
 67                 last[u]=v[f[u]] ? f[u] : last[f[u]];
 68             }
 69         }
 70     }
 71     void solve(int j)
 72     {
 73         if(!j) return;
 74         if(v[j])
 75         {
 76             ans+=v[j];
 77             v[j]=0;
 78         }
 79         solve(last[j]);
 80     }
 81     void find(char* T)
 82     {
 83         int n=strlen(T),j=0;
 84         getFail();
 85         for(int i=0;i<n;i++)
 86         {
 87             //while(j&&!chd[j][*T-'a']) j=f[j];
 88             j=chd[j][T[i]-'a'];
 89             if(v[j]) solve(j);
 90             else if(last[j]) solve(last[j]);
 91         }
 92     }
 93 }ac;
 94  
 95 int main()
 96 {
 97     int t,n;
 98     char dic[100],str[1100000];
 99     scanf("%d",&t);
100     while(t--)
101     {
102         ac.init();
103         scanf("%d",&n);
104         while(n--)
105         {
106             scanf("%s",dic);
107             ac.insert(dic);
108         }
109         scanf("%s",str);
110         ac.find(str);
111         printf("%d\n",ac.ans);
112     }
113     return 0;
114 }
View Code

 7.7 扩展KMP

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 //const int maxn=1e5+10;
 4 //int Next[maxn];
 5 //int ret[maxn];
 6 //
 7 ////扩展kmp求a为模式串,b为文本串的,b的所有后缀对a的最长公共前缀
 8 //void extendedKMP(char *a,char *b,int M,int N,int *Next,int *ret){
 9 //    int i,j,k;
10 //    for(j=0;1+j<M&&a[j]==a[1+j];j++);
11 //    Next[1]=j;
12 //    k=1;
13 //    for(i=2;i<M;i++){
14 //        int Len=k+Next[k],L=Next[i-k];
15 //        if(L<Len-i){
16 //            Next[i]=L;
17 //        }else {
18 //            for(j=max(0,Len-i);i+j<M&&a[j]==a[i+j];j++);
19 //            Next[i]=j;
20 //            k=i;
21 //        }
22 //    }
23 //
24 //    for(j=0;j<N&&j<M&&a[j]==b[j];j++);
25 //    ret[0]=j;
26 //    k=0;
27 //    for(i=1;i<N;i++){
28 //        int Len=k+ret[k],L=Next[i-k];
29 //        if(L<Len-i){
30 //            ret[i]=L;
31 //        }else {
32 //            for(i=max(0,Len-i);j<M&&i+j<N&&a[j]==b[i+j];j++);
33 //            ret[i]==j;k=i;
34 //        }
35 //    }
36 //
37 //}
38 const int maxn=100010;   //字符串长度最大值
39 int next[maxn],ex[maxn]; //ex数组即为extend数组
40 //预处理计算next数组
41 void GETNEXT(char *str)
42 {
43     int i=0,j,po,len=strlen(str);
44     next[0]=len;//初始化next[0]
45     while(str[i]==str[i+1]&&i+1<len)//计算next[1]
46     i++;
47     next[1]=i;
48     po=1;//初始化po的位置
49     for(i=2;i<len;i++)
50     {
51         if(next[i-po]+i<next[po]+po)//第一种情况,可以直接得到next[i]的值
52         next[i]=next[i-po];
53         else//第二种情况,要继续匹配才能得到next[i]的值
54         {
55             j=next[po]+po-i;
56             if(j<0)j=0;//如果i>po+next[po],则要从头开始匹配
57             while(i+j<len&&str[j]==str[j+i])//计算next[i]
58             j++;
59             next[i]=j;
60             po=i;//更新po的位置
61         }
62     }
63 }
64 //计算extend数组,s1为文本串,s2为模式串,求s1的所有后缀对s2的最长公共前缀
65 void EXKMP(char *s1,char *s2)
66 {
67     int i=0,j,po,len=strlen(s1),l2=strlen(s2);
68     GETNEXT(s2);//计算子串的next数组
69     while(s1[i]==s2[i]&&i<l2&&i<len)//计算ex[0]
70     i++;
71     ex[0]=i;
72     po=0;//初始化po的位置
73     for(i=1;i<len;i++)
74     {
75         if(next[i-po]+i<ex[po]+po)//第一种情况,直接可以得到ex[i]的值
76         ex[i]=next[i-po];
77         else//第二种情况,要继续匹配才能得到ex[i]的值
78         {
79             j=ex[po]+po-i;
80             if(j<0)j=0;//如果i>ex[po]+po则要从头开始匹配
81             while(i+j<len&&j<l2&&s1[j+i]==s2[j])//计算ex[i]
82             j++;
83             ex[i]=j;
84             po=i;//更新po的位置
85         }
86     }
87 }
88 
89 int main()
90 {
91     char *a="aaaabaa";
92     char *b="aaaaaaa";
93     EXKMP(a,b);
94     for(int i=0;i<7;i++){
95         printf("%d %d\n",next[i],ex[i]);
96     }
97 }
View Code

 

 7.8 华丽的hash

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 typedef unsigned long long ull;
 6 ull base=131;
 7 ull a[10010];
 8 char s[10010];
 9 int n,ans=1;
10 ull hashs(char s[])
11 {
12     int len=strlen(s);
13     ull ans=0;
14     for (int i=0;i<len;i++)
15         ans=ans*base+(ull)s[i];
16     return ans&0x7fffffff;
17 }
18 main()
19 {
20     scanf("%d",&n);
21     for (int i=1;i<=n;i++)
22     {
23         scanf("%s",s);
24         a[i]=hashs(s);
25     }
26     sort(a+1,a+n+1);
27     for (int i=2;i<=n;i++)
28         if (a[i]!=a[i-1])
29             ans++;
30     printf("%d\n",ans);
31 }
32  
一般hash
 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 typedef unsigned long long ull;
 6 ull base=131;
 7 ull a[10010];
 8 char s[10010];
 9 int n,ans=1;
10 ull mod=19260817;
11 ull hashs(char s[])
12 {
13     int len=strlen(s);
14     ull ans=0;
15     for (int i=0;i<len;i++)
16         ans=(ans*base+(ull)s[i])%mod;
17     return ans;
18 }
19 main()
20 {
21     scanf("%d",&n);
22     for (int i=1;i<=n;i++)
23     {
24         scanf("%s",s);
25         a[i]=hashs(s);
26     }
27     sort(a+1,a+n+1);
28     for (int i=2;i<=n;i++)
29         if (a[i]!=a[i-1])
30             ans++;
31     printf("%d\n",ans);
32 }
33  
单hash
 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 typedef unsigned long long ull;
 6 ull base=131;
 7 struct data
 8 {
 9     ull x,y;
10 }a[10010];
11 char s[10010];
12 int n,ans=1;
13 ull mod1=19260817;
14 ull mod2=19660813;
15 ull hash1(char s[])
16 {
17     int len=strlen(s);
18     ull ans=0;
19     for (int i=0;i<len;i++)
20         ans=(ans*base+(ull)s[i])%mod1;
21     return ans;
22 }
23 ull hash2(char s[])
24 {
25     int len=strlen(s);
26     ull ans=0;
27     for (int i=0;i<len;i++)
28         ans=(ans*base+(ull)s[i])%mod2;
29     return ans;
30 }
31 bool comp(data a,data b)
32 {
33     return a.x<b.x;
34 }
35 main()
36 {
37     scanf("%d",&n);
38     for (int i=1;i<=n;i++)
39     {
40         scanf("%s",s);
41         a[i].x=hash1(s);
42         a[i].y=hash2(s);
43     }
44     sort(a+1,a+n+1,comp);
45     for (int i=2;i<=n;i++)
46         if (a[i].x!=a[i-1].x || a[i-1].y!=a[i].y)
47             ans++;
48     printf("%d\n",ans);
49 }
双hash
 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 typedef unsigned long long ull;
 6 ull base=131;
 7 ull a[10010];
 8 char s[10010];
 9 int n,ans=1;
10 ull mod=212370440130137957ll;
11 ull hashs(char s[])
12 {
13     int len=strlen(s);
14     ull ans=0;
15     for (int i=0;i<len;i++)
16         ans=(ans*base+(ull)s[i])%mod;
17     return ans;
18 }
19 main()
20 {
21     scanf("%d",&n);
22     for (int i=1;i<=n;i++)
23     {
24         scanf("%s",s);
25         a[i]=hashs(s);
26     }
27     sort(a+1,a+n+1);
28     for (int i=2;i<=n;i++)
29         if (a[i]!=a[i-1])
30             ans++;
31     printf("%d\n",ans);
32 }
大hash
 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 typedef unsigned long long ull;
 6 ull base=131;
 7 ull po[100010],hs[100010*100];
 8 char s1[100010],s2[100010*100];
 9 int n,ans=1,T;
10 ull geth(int l,int r)
11 {
12     return (ull)hs[r]-po[r-l+1]*hs[l-1];
13 }
14 main()
15 {
16     freopen("oulipo.in","r",stdin);
17     freopen("oulipo.out","w",stdout);
18     po[0]=1;
19     for (int i=1;i<=10010-5;i++)
20         po[i]=po[i-1]*base;
21     scanf("%d",&T);
22     while(T--)
23     {
24         scanf("%s%s",s1+1,s2+1);
25         int l1=strlen(s1+1),l2=strlen(s2+1);
26         ull a1=0,ans=0;
27         for (int i=1;i<=l1;i++)
28             a1=a1*base+(ull)s1[i];
29         for (int i=1;i<=l2;i++)
30             hs[i]=hs[i-1]*base+s2[i];
31         for (int i=1;i+l1-1<=l2;i++)
32             if (a1==geth(i,i+l1-1))
33                 ans++;
34         printf("%d\n",ans);
35     }
36 }
hash字符串匹配
 1 写到这里突然发现hash好像可以暴力水过很多字符串算法。。
 2 
 3 1、kmp
 4 
 5 问题:给两个字符串S1,S2,求S2是否是S1的子串,并求S2在S1中出现的次数
 6 
 7 把S2 Hash出来,在S1里找所有长度为|S2||S2|的子串,Hash比较。效率O(|S1|)O(|S1|)
 8 
 9 2、AC自动机
10 
11 问题:给N个单词串,和一个文章串,求每个单词串是否是文章串的子串,并求每个单词在文章中出现的次数。
12 
13 把每一个单词hash成整数,再把文章的每一个子串hash成整数,接下来只需要进行整数上的查找即可。
14 
15 复杂度:O(|A|2+|S|)O(|A|2+|S|)
16 
17 用AC自动机可以做到O(|A|+|S|)O(|A|+|S|)的复杂度,|S||S|是单词串总长,|A||A|是文章长度
18 
19 3、后缀数组
20 
21 问题:给两个字符串S1,S2,求它们的最长公共子串的长度。
22 
23 将S1的每一个子串都hash成一个整数,将S2的每一个子串都hash成一个整数
24 
25 两堆整数,相同的配对,并且找到所表示的字符串长度最大的即可。
26 
27 复杂度:O(|S1|2+|S2|2)O(|S1|2+|S2|2)
28 
29 用后缀数组可以优化到O(|S|log|S|)O(|S|log|S|)
30 
31 4、马拉车
32 
33 问题:给一个字符串S,求S的最长回文子串。
34 
35 先求子串长度位奇数的,再求偶数的。枚举回文子串的中心位置,然后二分子串的长度,直到找到一个该位置的最长回文子串,不断维护长度最大值即可。
36 
37 复杂度:O(|S|log|S|)O(|S|log|S|)
38 
39 用manacher可以做到O(|S|)O(|S|)的复杂度
40 
41 5、扩展kmp
42 
43 问题:给一个字符串S,求S的每个后缀与S的最长公共前缀
44 
45 枚举每一个后缀的起始位置,二分长度,求出每个后缀与S的最长公共前缀。
46 
47 复杂度:O(|S|log|S|)O(|S|log|S|)
48 
49 用extend-kmp可以做到O(|S|)
hash水字符串

 

 

八、杂

8.1 三分求极大极小点

 1 int SanFen(int l,int r) //找凸点  
 2 {  
 3     while(l < r-1)  
 4     {  
 5         int mid  = (l+r)/2;  
 6         int mmid = (mid+r)/2;  
 7         if( f(mid) > f(mmid) )  
 8             r = mmid;  
 9         else  
10             l = mid;  
11     }  
12     return f(l) > f(r) ? l : r;  
13 }  
整数求凸点
 1 double three_devide(double low,double up)  
 2 {  
 3     double m1,m2;  
 4     while(up-low>=eps)  
 5     {  
 6         m1=low+(up-low)/3;  
 7         m2=up-(up-low)/3;  
 8         if(f(m1)<=f(m2))  
 9             low=m1;  
10         else  
11             up=m2;  
12     }  
13     return (m1+m2)/2;  
14 }  
小数求凸点
 1 int SanFen(int l,int r) //找凸点  
 2 {  
 3     while(l < r-1)  
 4     {  
 5         int mid  = (l+r)/2;  
 6         int mmid = (mid+r)/2;  
 7         if( f(mid) > f(mmid) )  
 8             l = mid;  
 9         else  
10             r = mmid;  
11     }  
12     return f(l) > f(r) ? l : r;  
13 }  
整数求凹点
 1 double three_devide(double low,double up)  
 2 {  
 3     double m1,m2;  
 4     while(up-low>=eps)  
 5     {  
 6         m1=low+(up-low)/3;  
 7         m2=up-(up-low)/3;  
 8         if(f(m1)<=f(m2))  
 9             up=m2;  
10         else  
11             low=m1;  
12     }  
13     return (m1+m2)/2;  
14 }  
小数求凹点

 8.2 欧拉函数递推

 1 void Euler(){
 2     phi[1] = 1;
 3     for(int i = 2; i < N; i ++){
 4         if(!phi[i]){
 5             phi[i] = i-1;
 6             prime[tot ++] = i;
 7         }
 8         for(int j = 0; j < tot && 1ll*i*prime[j] < N; j ++){
 9             if(i % prime[j]) phi[i * prime[j]] = phi[i] * (prime[j]-1);
10             else{
11                 phi[i * prime[j] ] = phi[i] * prime[j];
12                 break;
13             }
14         }
15     }
16     sum[1]=0;
17     for(int i=2;i<N/2;i++){
18         sum[i]=phi[2*i]/2;
19         sum[i]=sum[i-1]+sum[i];
20     }
21 }
View Code

 

posted on 2018-05-05 10:19  Best_Efforts  阅读(527)  评论(0编辑  收藏  举报

导航