一些模板的实现(按字典序排序)
埃式筛法(优化)
应该比普通的快了一倍左右。
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);
}