冲刺NOIp2016算法模板
程序大部分没经过编译和测评,欢迎在评论区指出本文中的错误
另:点开右下角像WIFI一样的标志进入RSS模式即可避免索引目录鬼畜的问题(可能需要向下翻一会才能找到本篇文章)NOIp竞赛中还可能会用到的模板:Tarjan等,请大家注意一下
记得考前一定要练好DFS和记忆化DFS!!骗分必用!
Catalogue:
数据结构
栈
int strack[maxn];
int head;
bool b[maxn];
void push(int x)
{
strack[++head]=x;
b[x]=true;
};
int pop()
{
int ret;
ret=strack[head--];
b[ret]=false;
return ret;
};
bool empty()
{
return head>0;
}
队列
int queue[2*maxn];
int tail,head;
bool b[maxn];
void push(int x)
{
queue[++tail]=x;
bool[x]=true;
};
int pop()
{
int ret;
ret=queue[++head];
b[ret]=false;
return ret;
};
bool empty()
{
return head>=tail;
};
当然有的时候你手写的数据结构需要比较大的空间,这样队列就会造成很多损失,所以相应的就有两种解决方法:一:STL;二:循环队列,只需改两个地方(代码如下);
head=(head+1)%n+1;//把head++改
tail=(tail+1)%n+1;//把tail++改
树状数组
int lowbit(int x)
{
return x&-x;
};
int getsum(int n) //求1~n见的和
{
int ret=0;
while(n)
{
ret+=c[n];
n-=lowbit(n);
};
return ret;
};
void add(int n,int x) //给a[n]加上x
{
a[n]+=x;
while(n<=maxn)
{
c[n]+=x;
n+=lowbit(n);
应用模型:
- 树状数组求逆序对:
void update(int n)
{
while(n<=maxn)
{
c[n]+=1;
n+=lowbit(n);
};
};
for(int i = 1; i <= n; ++i) //主程序里面加上这个
{
update(reflect[i]);
ans += i - getsum(reflect[i]);//reflect是离散化后的数组
}
单调队列
- 例题:Luogu P1823 音乐会的等待(我写了一篇此题的解题报告)
以下单调队列的标程就用的音乐会的等待的。
#include <iostream>
#include <cstdio>
using namespace std;
const int maxn=500005;
int n,l,ans;
long long q[maxn],bef[maxn];
int main()
{
cin>>n;
q[0]=-1;
long long a;
for(int i=1;i<=n;i++)
{
cin>>a;
while(l>0&&a>q[l])
{
l--;
ans++;
};
if(l!=0)
{
if(a!=q[l])ans++;else
{
ans+=bef[l];
if(bef[l]<l)ans++;
};
};
l++;q[l]=a;
if(q[l-1]==a)bef[l]=bef[l-1]+1;else bef[l]=1;
};
cout<<ans;
return 0;
}
STL
关于每个STL我只会写一下是什么,怎么用(举例子的形式),不会说的太细
Vector
不定长度数组
#include <vector>
vector<int> first; //第一种定义方法
int myints[]={
16,2,77,29};
vector<int> second(myints,myints+4);//第二种定义方法
sort(second.begin(),second.end());//对vector排序
a=second[i];//可以这么使用
//以下是对vector的操作
Vector<int> opt;
opt.begin(); //返回起始地址
opt.end(); //返回结束地址
opt.size(); //返回大小
opt.empty(); //返回是否vector为空
opt.back(); //返回最后一个push进的数
opt.pop_back(); //把最后一个数弹出(不返回)
opt.push_back(int x);//把x从后面push进去
opt.erase(opt.begin(),opt.begin()+3);//删掉前三个元素
opt.erase(opt.begin()+5);//删掉第6个元素
Queue
队列,操作与Stack一样。
Priority_queue
相当于堆
#include <queue>
priority_queue<int> Bigheap;//定义一个大根堆
priority_queue<int,vector<int>,greater<int> > Smallheap;//定义一个小根对(注意两个尖括号间有空格)
//以下是操作
priority_queue<int> opt;
opt.top();//返回堆顶元素的值(不弹出)
opt.pop();//弹出堆顶元素(无返回值)
opt.push(x);
Stack
stack<int> opt;
opt.front();//返回
opt.size();
opt.empty();
opt.push();
opt.pop();//弹出
Deque
双向队,操作与Stack一样
Bitset
压位神器,只普及一下,不会用。
Set
set<int> first;
int myints[]= {
10,20,30,40,50};
set<int> second (myints,myints+5);
set<int> third (second);
set<int> fourth (second.begin(), second.end());
third.rbegin(); third.rend();//rend相当于begin,rbegin相当于end
third.size();//返回大小
third.insert(60);
third.erase(it);
third.erase(50);//删除元素'50'
third.find(10);//找元素'10'
third.lower_bound(30); third.upper_bound(30);//'30'出现的第一个位置/最后一个位置
third.clear();//清除
Multiset
与Set用法一样,只是允许重复元素。
Map
map<char,int> first;
first[‘a’] = 10;
first.insert(make_pair(‘b’,20));
it++; ++it; it--; --it;
first.erase(1);//删除元素
firstt.count(1);//看有没有关系
Algorithm里其他好用的函数
Next_permutation
int a[]={
1,2,3,4};
next_permutation(a,a+3);//下一个全排列
//现在a数组变成了:1 2 4 3
Lower_bound与Upper_bound
lower_bound(first,last,val);//有返回值
upper_bound(first,last,val);
Merge
merge (first,first+5,second,second+5,v.begin(),compare);
sort
bool compare(int a,int b)
{
return a<b;
};//compare函数的例子
sort(起始地址,结束地址,compare函数);
Reverse
Reverse(myvector.begin(),myvector.end());
Unique
bool myfunction (int i, int j)
{
return (i==j);
}
unique(起始地址,结束地址,去重条件函数);//按照函数里面编写的规则去重,当然也可以没有第三个参数
Random_shuffle
留一个概念,不会用,生成数据的时候用。
数论
快速幂
普通快速幂
#define ull unsigned long long
ull qpow(ull x,ull y,ull p) // x^y mod p
{
ull ret=1;
while(y)
{
if(y&1)ret = ret * x % p;
x=x*x%p;
y>>=1;
};
return ret;
}
矩阵快速幂
matrix operator *(matrix m1,matrix m2)//重载运算符
{
assert(m1.m==m2.n);
matrix res;
res.n=m1.n; res.m=m2.m;
for(int i=0;i<m1.n;i++)
for(int j=0;j<m2.m;j++)
for(int k=0;k<m1.m;k++)
res.mat[i][j]+=m1.mat[i][k]*m2.mat[k][j];
return res;
}
matrix matrix_pow(matrix x,int y)
{
matrix res;
res.n=res.m=2;
res.mat[0][0]=res.mat[1][1]=1;
while(y)
{
if(y&1)res=res*x;
x=x*X;
y>>=1;
}
return res;
}
筛法求素数
欧拉筛法
int tot=0;
void euler(int n)
{
memset(check,0,sizeof(check));
for(int i=1;i<=n;i++)
{
if(!check[i])prime[++tot]=i;
for(int k=1;k<=tot;k++)
{
if(i*prime[k]>n)break;
check[i*prime[k]]=1;
if(i%prime[k]==0)break;
};
};
};
应用举例:
- 模板题 : Luogu P3383
验证素数
普通方法
bool flag=true;
for(int i=1;i<=trunc(sqrt(prime));i++)
if(prime%i==0)flag=false;//置不是素数标志
Miller-Rabin
时间复杂度: O(k∗log2n) k是次数(见下文)
难度:★★★
这里只说明一下原理,关于代码,自行百度吧。
- 根据费马小定理,随机选一个数 a∈(1,p) ,若