zoukankan      html  css  js  c++  java
  • 东拼西凑的模板·持续更新中

    一.常用算法

    文中代码大量来自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] = {''}, num2[100] = {''};
     17     printf("Please input two nunber(less than 100 digits):
    > ");
     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
    ");
     26             return 1;
     27         }
     28 
     29         if(checkNum(num1) or checkNum(num2))
     30         {
     31             printf("ERROR: input must be an Integer
    ");
     32             return 1;
     33         }
     34 
     35         printf("num1:	%s
    num2:	%s
    ", num1, num2);
     36 
     37         result = multiBigInteger(num1, num2);
     38 
     39         /* 输出结果result,result[0]保存着result的长度,
     40          * 所以下标要从1开始 */
     41         printf("result:	");
     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("
    ");
     58         printf("
    Please input two nunber(less than 100 digits):
    > ");
     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
    num2Len:%d
    ", 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
    ",A[0][5-n]);
            }
            else{
                X=qpow(X,n-3);
                C=mul(Y,X);
                printf("%lld
    ",(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
    ",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("
    ");
    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
    ");
    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
    ",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
    ");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
    "); continue;}
    31         P=(B-A) * (a / (a+b)) + A;
    32         if(P.y>C.y || P.y<D.y){ printf("0.00
    ");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
    ");continue;}
    37             MA=B + (A-B) * ((C.y-B.y)/(A.y-B.y));
    38             printf("%.2lf
    ",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
    ");continue; }
    44             MC=D+(C-D) * ((A.y-D.y) / (C.y-D.y));
    45             printf("%.2lf
    ",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
    ", 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
    ");
    733         else printf("n0
    ");
    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
    ",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("无解!
    ");
     97             else if (free_num == -2) printf("有浮点数解,无整数解!
    ");
     98             else if (free_num > 0){
     99                 printf("无穷多解! 自由变元个数为%d
    ", free_num);
    100                 for (i = 0; i < var; i++){
    101                     if (free_x[i]) printf("x%d 是不确定的
    ", i + 1);
    102                     else printf("x%d: %d
    ", i + 1, x[i]);
    103                 }
    104             }else{
    105                 for (i = 0; i < var; i++){
    106                     printf("x%d: %d
    ", i + 1, x[i]);
    107                 }
    108             }
    109             printf("
    ");
    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
    ", 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
    ", 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.
    ");
    55         else
    56             printf("Ollie wins.
    ");
    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
    ",_max);
     96             else
     97                 printf("%d no
    ",_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
    ",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
    ",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
    ",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
    ",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
    ",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
    ",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
    ",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("
    ");
    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
    ");
    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
    ");
    23             for(int i = 0; i < tp; i++)
    24                 printf("%lld%c", link[i], i == tp-1? '
    ': ' ');
    25         }
    26         else {
    27             printf("NO
    ");
    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 <<" 
    ";
        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
    ",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
    ",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
    ", 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
    ", 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
    ", 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] = '';
    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
    ", 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("
    ");
    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("
    ");
    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
    ",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
    ",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
    ",max+1);
    189       else printf("0
    ");
    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
    ",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
    ",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
    ",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] == '') 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
    ",text);
    67         else printf(""%s" not in it
    ",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] == '') 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
    ",text);
    67         else printf(""%s" not in it
    ",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
    ",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
    ",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
    ",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
    ",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
    ",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
    ",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
    ",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
    ",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
  • 相关阅读:
    Latex (1)
    linux/unix command
    函数类型和函数指针类型(摘自 linux c编程一站式学习)
    emacs 剪切板
    Centos 常见问题汇总
    makefile(摘自linux_c编程一站式学习)
    [转]DIV布局之三行三列之高度自适应
    ASP.Net新手项目经验谈
    获取中文首字母的方法
    还是不会伪装
  • 原文地址:https://www.cnblogs.com/bestefforts/p/8993859.html
Copyright © 2011-2022 走看看