一些模板(按字典序排序)

一些模板的实现(按字典序排序)

埃式筛法(优化)

应该比普通的快了一倍左右。

typedef long long ll;
int p[100000000];
int Max1=100000000;
void prime()
{
    p[2]=1;
    for(ll i=3;i<Max1;i+=2)p[i]=1;
    ll l=sqrt(Max1);
    for(ll i=3;i<l;i+=2)
    {
        if(p[i])
        {
            ll k=2*i;
            for(ll j=3*i;j<=Max1;j+=k)p[j]=0;
        }
    }
    return ;
}

fft快速傅里叶变换:

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
const int MAXN=1e7+10;
inline int read()
{
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
const double Pi=acos(-1.0);
struct complex
{
    double x,y;
    complex (double xx=0,double yy=0){x=xx,y=yy;}
}a[MAXN],b[MAXN];
complex operator + (complex a,complex b){ return complex(a.x+b.x , a.y+b.y);}
complex operator - (complex a,complex b){ return complex(a.x-b.x , a.y-b.y);}
complex operator * (complex a,complex b){ return complex(a.x*b.x-a.y*b.y , a.x*b.y+a.y*b.x);}//不懂的看复数的运算那部分 
int N,M;
int l,r[MAXN];
int limit=1;
void fast_fast_tle(complex *A,int type)
{
    for(int i=0;i<limit;i++) 
        if(i<r[i]) swap(A[i],A[r[i]]);//求出要迭代的序列 
    for(int mid=1;mid<limit;mid<<=1)//待合并区间的中点
    {
        complex Wn( cos(Pi/mid) , type*sin(Pi/mid) ); //单位根 
        for(int R=mid<<1,j=0;j<limit;j+=R)//R是区间的右端点,j表示前已经到哪个位置了 
        {
            complex w(1,0);//幂 
            for(int k=0;k<mid;k++,w=w*Wn)//枚举左半部分 
            {
                 complex x=A[j+k],y=w*A[j+mid+k];//蝴蝶效应 
                A[j+k]=x+y;
                A[j+mid+k]=x-y;
            }
        }
    }
}
int main()
{
    int N=read(),M=read();
    for(int i=0;i<=N;i++) a[i].x=read();
    for(int i=0;i<=M;i++) b[i].x=read();
    while(limit<=N+M) limit<<=1,l++;
    for(int i=0;i<limit;i++)
        r[i]= ( r[i>>1]>>1 )| ( (i&1)<<(l-1) ) ;
    // 在原序列中 i 与 i/2 的关系是 : i可以看做是i/2的二进制上的每一位左移一位得来
    // 那么在反转后的数组中就需要右移一位,同时特殊处理一下复数 
    fast_fast_tle(a,1);
    fast_fast_tle(b,1);
    for(int i=0;i<=limit;i++) a[i]=a[i]*b[i];
    fast_fast_tle(a,-1);
    for(int i=0;i<=N+M;i++)
        printf("%d ",(int)(a[i].x/limit+0.5));
    return 0;
}

KMP

用来搞字符串配对的。

void GetNextval(char* p, int next[])  
{  
    int pLen = strlen(p);  
    next[0] = -1;  
    int k = -1;  
    int j = 0;  
    while (j < pLen - 1)  
    {  
        if (k == -1 || p[j] == p[k])  
        {  
            ++j;  
            ++k;   
            if (p[j] != p[k])  
                next[j] = k;
            else  
                next[j] = next[k];  
        }  
        else  
        {  
            k = next[k];  
        }  
    }  
} 
int KmpSearch(char* s, char* p)  
{  
    int i = 0;  
    int j = 0;  
    int sLen = strlen(s);  
    int pLen = strlen(p);  
    while (i < sLen && j < pLen)  
    {  
        if (j == -1 || s[i] == p[j])  
        {  
            i++;  
            j++;  
        }  
        else  
        {  
        	j = next[j];  
        }  
    }  
    if (j == pLen)  
        return i - j;  
    else  
        return -1;  
}  

快速幂

int fastPow(int a, int n){
    int base = a;        
    int res = 1; 
    while(n) {
        if(n & 1)   //如果n的最后一位是1,表示这个地方需要乘
              res *= base;  
        base *= base;       //推算乘积,a2 --> a4 --> a8--> a16...
        n >>= 1;     //n右移一位,把刚处理过的n的最后一位去掉
    }
    return res;
}

扩展欧几里得

求方程ax+by=gcd(a,b)的一个特解(x0, y0)

void extend_gcd(int a, int b, int &x, int &y){ 
                          //返回x,y,即一个特解(x0, y0)
    if(b==0) {
        x=1, y=0;      return ;
    }
    extend_gcd(b, a%b, x, y);
    int tmp = x;
    x = y;
    y = tmp - (a/b)*y;
}

(1)判断ax+by=n有解
(2)用扩展欧几里得求 ax+by=gcd(a,b)的特解(x0, y0)
(3)在ax0+by0=gcd(a,b)的两边同乘n/gcd(a,b),得:
ax0n/gcd(a,b)+by0n/gcd(a,b)=n
(4)对照ax+by=n,一个特解是:
x0 n /gcd(a,b), y0 n /gcd(a,b)

特例1:
在这里插入图片描述

特例2:
逆元

int mod_inverse(int a, int m){
    int x, y;
    extend_gcd(a, m, x, y);
    return (m + x % m) % m;    //x可能是负数
}

求逆元的另一个方法:费马小定理。

母函数:

通过三阶循环来实现,这里展示的是一个从x的一次方到二次方到三次方…n次方的母函数。

#include <iostream>
using namespace std;
const int _max = 10001; 
int c1[_max], c2[_max];   
int main()
{
	int nNum;   
	int i, j, k;
 
	while(cin >> nNum)
	{
		for(i=0; i<=nNum; ++i)//第一个式子 
		{
			c1[i] = 1;
			c2[i] = 0;
		}
		for(i=2; i<=nNum; ++i)
		{
 
			for(j=0; j<=nNum; ++j)
				for(k=0; k+j<=nNum; k+=i)
				{
					c2[j+k] += c1[j];
				}
				for(j=0; j<=nNum; ++j)
				{
					c1[j] = c2[j];
					c2[j] = 0;
				}
		}
		cout << c1[nNum] << endl;
	}
	return 0;
}

rmq(区间最值查询):

这个是用来找一段数据内某个区间内的极大值或者极小值。
通过二进制来实现,十分巧妙。

	代码实现:
#include<bits/stdc++.h>

using namespace std;
#define MAX 10000
int dp[MAX][MAX],a[MAX],b[MAX],n;
void rmq()
{
    for(int i=0;i<n;i++)dp[i][0]=a[i];
    for(int j=1;(1<<j)<n;j++)
    {
        for(int i=0;i+(1<<j)-1<n;i++)
        {
            dp[i][j]=min(dp[i][j-1],dp[i+(1<<j-1)][j-1]);
        }
    }
}
int cz(int o,int p)
{
    int k=log2(p-o+1);
    return min(dp[o][k],dp[p-(1<<k)+1][k]);
}
int main()
{
    cin>>n;
    for(int i=0;i<n;i++)cin>>a[i];
    rmq();
    for(int i=0;i<n;i++)
    {
        for(int j=i;j<n;j++)
        {
            cout<<cz(i,j)<<' ';
        }
        cout<<endl;
    }
}

输入输出优化(面对一长串数字):

这主要针对的是一长串的数字(就是有许多的数字)(一般情况下也是这样一次给你好多组数据),这样输入可以节约很多时间。

inline int read()
{
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
void print(int x)
{
    if(x<0)putchar('-'),x=-x;
    if(x>9)print(x/10);
    putchar(x%10+'0');
}

Sunday算法(字符串配对)

比kpm与bm快。

int Sunday(const char *str1, const char *str2)
{
    int str1_len = strlen(str1);
    int str2_len = strlen(str2);
    int i = 0;
    int j = 0;
    enum{FALSE,TRUE};
    int Y = FALSE;   

    if(str1 == NULL || str2 == NULL){
    return -1;
    }

    while(i < str1_len && j < str2_len){
        if(str1[i] == str2[j])
        {
        	i++;
        	j++; 
        }
        else
        {
        	int num = i - j + str2_len ;
        	for(j = str2_len-1; j >= 0; j--)
        	{
        		if(str1[num] == str2[j])
        		{
            		i = num - j;
                	Y = TRUE;
            		break;
            	}
        	}
        	if(Y == FALSE)
        	{
        		i = num + 1; 
        	}
        	Y = FALSE;
        	j = 0;
        }
    }       
    if(i == str1_len){
    return -1;
    }
    else
    return i - str2_len;
}

通用外框:

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
#define pc putchar
inline int read()
{
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
void print(int x)
{
    if(x<0)putchar('-'),x=-x;
    if(x>9)print(x/10);
    putchar(x%10+'0');
}
const int MAXN=1e7+10;

希尔排序:

这也是一种比较快的排序方法,所说有时比快排还要快,至于是不是真的我就不知道了,不过这个不能直接引用。

//函数功能,希尔排序算法对数字递增排序
//函数参数,数列起点,数列终点
void shell_sort(const int start, const int end) {
    int increment = end - start + 1;    //初始化划分增量
    int temp{ 0 };
    do {    //每次减小增量,直到increment = 1
        increment = increment / 3 + 1;
        for (int i = start + increment; i <= end; ++i) {    //对每个划分进行直接插入排序
            if (numbers[i - increment] > numbers[i]) {
                temp = numbers[i];
                int j = i - increment;
                do {    //移动元素并寻找位置
                    numbers[j + increment] = numbers[j];
                    j -= increment;
                } while (j >= start && numbers[j] > temp);
                numbers[j + increment] = temp;  //插入元素
            }
        }
    } while (increment > 1);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值