1.基础算法
1.排序。归并排序求逆序对。快排
2.前缀和 差分。前缀和,快速求出一段区间的和。差分,快速对一段区间修改。前缀和计算l-1,差分修改r+1。注意二维别写错
3.二分。注意如果是r=mid-1,,则mid要l+r+1>>1。
4.高精度
5.双指针算法。
6.位运算。lowbit
7.离散化
2.基础数据结构
1.单链表,h,e,ne,idx;
2.双链表:
//这里填你的代码^^
#include<iostream>
#include<cstring>
using namespace std;
const int N=100010;
int l[N],r[N],e[N],idx;
int m;
void init()
{
//0是左端点,1是右端点
l[1]=0;
r[0]=1;
idx=2;
}
void insert(int k,int x)
{
e[idx]=x;
l[idx]=k;
r[idx]=r[k];
l[r[k]]=idx;r[k]=idx++;
}
void remove(int k)
{
r[l[k]]=r[k];
l[r[k]]=l[k];
}
int main()
{
init();
cin>>m;
while(m--)
{
string op;
int k,x;
cin>>op;
if(op=="L") cin>>x,insert(0,x);
else if(op=="R") cin>>x,insert(l[1],x);
else if(op=="D") cin>>k,remove(k+1);
else if(op=="IR") cin>>k>>x,insert(k+1,x);
else cin>>k>>x, insert(l[k+1],x);
}
for(int i=r[0];i!=1;i=r[i]) cout<<e[i]<<" ";
return 0;
}
//注意代码要放在两组三个点之间,才可以正确显示代码高亮哦~
作者:yankai
链接:https://www.acwing.com/activity/content/code/content/3400144/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
3.栈
单调栈:求出第一个小于当前数、大于当前数的数。
4.队列
单调队列:维护滑动窗口最大值最小值。
5.KMP
6.Trie
7.并查集:
int find(int x)
{
if(p[x]!=x)
{
int t=find(p[x]);
d[x]+=d[p[x]];
p[x]=t;
}
return p[x]
}
8.堆
从最后一个非叶节点向下调整
9.hash
3.图论
1.拓扑序——dp
2.spfa求负环——到i点最短路经过大于n个点
//这里填你的代码^^
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
const int N =1000010;
int h[N],e[N],w[N],ne[N],idx;
int dist[N],cnt[N];//存每个点最短路长度
int n,m;
bool st[N];
void add(int a,int b,int c)
{
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
int spfa()
{
queue<int> q;
for(int i=1;i<=n;i++)
{
st[i]=true;
q.push(i);
}
while(q.size())
{
int t=q.front();
q.pop();
st[t]=false;
for(int i=h[t];i!=-1;i=ne[i])
{
int j=e[i];
if(dist[j]>dist[t]+w[i])
{
dist[j]=dist[t]+w[i];
cnt[j]=cnt[t]+1;
if(cnt[j]>=n)
{
return true;
}
if(!st[j])
{
st[j]=true;
q.push(j);
}
}
}
}
return false;
}
int main()
{
cin>>n>>m;
memset(h,-1,sizeof h);
for(int i=0;i<m;i++)
{
int a,b,c;
cin>>a>>b>>c;
add(a,b,c);
}
if(spfa()) cout<<"Yes";
else cout<<"No";
return 0;
}
//注意代码要放在两组三个点之间,才可以正确显示代码高亮哦~
作者:yankai
链接:https://www.acwing.com/activity/content/code/content/3670027/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
3.最小生成树求法
4.匈牙利算法(st数组每轮更新)
//这里填你的代码^^
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N =510,M=100010;
int h[N],ne[M],e[M],idx;
bool st[N]; //表示本次循环右边该点是否被考虑过 每次不要重复搜一个点(因为一次循环内不需要再更改这个点的match)
int match[N]; //存储右边的点和左边的哪个点匹配
int n1,n2,m;
void add(int a,int b)
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
bool find(int x)
{
for(int i=h[x];i!=-1;i=ne[i])
{
int j=e[i];
if(!st[j]) //本次循环内没有考虑过j
{
st[j]=true;
if(match[j]==0||find(match[j])) //j没有匹配过,或者再find一次和j匹配的节点能匹配到新的
//代表这个j可以和当前这个x匹配
{
match[j]=x;
return true;
}
}
}
return false;
}
int main()
{
memset(h,-1,sizeof h);
cin>>n1>>n2>>m;
for(int i=0;i<m;i++)
{
int a,b;
cin>>a>>b;
add(a,b);
}
int res=0;
for(int i=1;i<=n1;i++)
{
memset(st,false,sizeof st);
if(find(i)) res++;//成功匹配
}
cout<<res;
return 0;
}
//注意代码要放在两组三个点之间,才可以正确显示代码高亮哦~
作者:yankai
链接:https://www.acwing.com/activity/content/code/content/3682284/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
5.dp
01背包,完全背包
多重背包:二进制优化,单调队列优化
这里先给出二进制优化:
注意不够二级次幂的要加上
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N =25000,M=2010;
int v[N],w[N];
int n,m;
int f[M];
int main()
{
cin>>n>>m;
int cnt=0;
for(int i=1;i<=n;i++)
{
int a,b,s;
cin>>a>>b>>s;
int k=1;
while(k<=s)
{
cnt++;
v[cnt]=a*k;
w[cnt]=b*k;
s-=k;k*=2;
}
if(s>0)
{
v[++cnt]=s*a; w[cnt]=b*s;
}
}
n=cnt;//n变为打包后的物品数量
for(int i=1;i<=cnt;i++)
for(int j=m;j>=v[i];j--)
f[j]=max(f[j],f[j-v[i]]+w[i]);
cout<<f[m];
}
分组背包:01背包+多一层遍历组内物品
//这里填你的代码^^
#include<iostream>
#include<algorithm>
using namespace std;
const int N =110;
int v[N][N],w[N][N],s[N];
int f[N];
int n,m;
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>s[i];
for(int j=1;j<=s[i];j++)
cin>>v[i][j]>>w[i][j];
}
for(int i=1;i<=n;i++)
for(int j=m;j>=0;j--)
for(int k=1;k<=s[i];k++)
if(v[i][k]<=j)
f[j]=max(f[j],f[j-v[i][k]]+w[i][k]);
cout<<f[m];
return 0;
}
//注意代码要放在两组三个点之间,才可以正确显示代码高亮哦~
作者:yankai
链接:https://www.acwing.com/activity/content/code/content/3818429/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
最长上升子序列的nlogn解法
贪心+二分
状态表示:长度为i的最长上升子序列所有结尾中,结尾最小min的) 即长度为i的子序列末尾最小元素是什么。
当遇到一个新元素,二分一下找出结尾小于该数的,,长度最长的序列,然后更新长度+1(和已经求出的长度+1的方案比较)
当初看这个的时候感觉好难想啊,,现在看来思路是:找出结尾小于该数长度最长的方案 其实是很自然的。
//这里填你的代码^^
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
//f[i]表示长度为i的最长上升子序列,末尾最小的数字。
//(长度为i的最长上升子序列所有结尾中,结尾最小min的) 即长度为i的子序列末尾最小元素是什么。
const int N =100010;
int a[N];
int f[N];
int n;
int main()
{
cin>>n;
for(int i=0;i<n;i++) cin>>a[i];
int len=0;
f[0]=-2e9;
for(int i=0;i<n;i++)
{
int l=0,r=len;
while(l<r)
{
int mid=l+r+1>>1;
if(f[mid]<a[i]) l=mid;
else r=mid-1;
}
len=max(len,r+1);
f[r+1]=a[i];
}
cout<<len;
return 0;
}
//注意代码要放在两组三个点之间,才可以正确显示代码高亮哦~
作者:yankai
链接:https://www.acwing.com/activity/content/code/content/3899911/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。