算法模板
怎么说呢,怕忘记,多记忆!!!
二维前缀和
// 二维前缀和
for(int i=1;i<N;i++){
for(int j=1;j<N;j++){
s[i][j] = s[i-1][j] + s[i][j-1] - s[i-1][j-1] + s[i][j];
}
}
int ans = 0;
// 在N*N的地图里面遍历 r*r 的底盘,使得地盘里面的和最高
for(int i=r;i<N;i++)
for(int j=r;j<N;j++)
ans = max(ans,s[i][j]-s[i-r][j]-s[i][j-r]+s[i-r][j-r]);
树状数组
void lowbit(int x){
return x &-x;
}
void add(int x,int v){
for(int i=x;i<=n;i+=lowbit(i))tr[i] += v;
}
int query(int x){
int ans = 0;
for(int i=x;i;i-=lowbit(i))ans += tr[i];
return ans;
}
线段树
int n,m;
int w[N];
struct node{
int l,r;
int sum;
}tr[N*4];
void pushup(int u){
tr[u].sum = tr[u<<1].sum + tr[u<<1|1].sum;
}
void build(int u,int l,int r){
if(l == r)tr[u] = {l,r,w[r]};
else {
tr[u] = {l,r};
int mid = l+r >> 1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
pushup(u);
}
}
int query(int u,int l,int r){
if(tr[u].l>=l&&tr[u].r<=r)return tr[u].sum;
int sum = 0;
int mid = tr[u].l + tr[u].r >> 1;
if(mid >= l) sum += query(u<<1,l,r);
if(mid<r) sum += query(u<<1|1,l,r);
return sum;
}
void modify(int u,int x,int v){
if(tr[u].l == tr[u].r)tr[u].sum += v;
else{
int mid = tr[u].l + tr[u].r >> 1;
if(mid >= x)modify(u<<1,x,v);
else modify(u<<1|1,x,v);
pushup(u);
}
}
KMP字符串匹配算法
for(int i=2,j=0;i<=n;i++){
while(j&& p[i] != p[j+1])j = ne[j];
if(p[i] == p[j+1])j++;
ne[i] = j;
}
for(int i=1,j=0;i<=m;i++){
while(j && s[i] != p[j+1]) j =ne[j];
if(s[i] == p[j+1])j++;
if(j == n){
cout << "匹配第N次:" << i-n << endl;
j = ne[j];
}
}
string 类API
// 字符串string api匹配
idx = s.find(p);
while(idx != std::string::npos) {
cout << idx << ' ';
idx = s.find(p, idx + 1);
}
//1、功能介绍:返回str在字符串中第一次出现的位置,从index开始查找,如果查找失败,则返回string::npos。
size_type find ( const basic_string &str, size_type index )
//2、功能介绍:返回str中任意字符在字符串中第一次出现的位置,从位置0开始查找。
size_type find_first_of ( const string& str, size_type pos = 0 )
//3、find_first_not_of功能与find_first_of()函数的功能正好相反。得到第一个不是该目标的下标
size_type find_first_not_of ( const string& str, size_type pos = 0 )
//4、find_last_of 与find_first_of()函数相比而言,其不同的地方在于:find_last_of()是找出最后一个相同的位置。
size_type find_last_of(...)
// string::npos的使用
string s = "abc";
if (s.find("b") != string::npos)
printf("字符串s中存在b字符~");
else
printf("字符串s中不存在b字符~");
//1、功能介绍:在p位置插入字符串s
string &insert(int p,const string &s)
//2、功能介绍:删除从p开始的n个字符,然后在p处插入字符串s
string &replace(int p, int n,const char *s)
//3、功能介绍:删除p开始的n个字符,返回修改后的字符串
string &erase(int p, int n)
//4、功能介绍:返回pos开始的n个字符组成的字符串
string substr(int pos, int n )
//5、功能介绍:交换当前字符串与s2的值
void swap(string &s2)
//6、功能介绍:把字符串s连接到当前字符串结尾
string &append(const char *s)
//7、功能介绍:当前字符串尾部加一个字符c
void push_back(char c)
超级方便的N皇后
#include<bits/stdc++.h>
using namespace std;
const int N = 110;
bool col[N],lie[N],d[N];
char g[N][N];
int n;
void dfs(int u){
if(u == n){
for(int i=0;i<n;i++)puts(g[i]);
puts("");
return ;
}
for(int i=0;i<n;i++){
if(!col[i]&&!lie[u+i]&&!d[n-u+i]){
g[u][i] = 'Q';
col[i]=lie[u+i] = d[n-u+i] = true;
dfs(u+1);
g[u][i] = '.';
col[i]=lie[u+i] = d[n-u+i] = false;
}
}
}
int main(){
cin >> n;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
g[i][j] = '.';
}
}
dfs(0);
return 0;
}
离散化(将一些稀疏的数据聚拢在一起)
#include<bits/stdc++.h>
using namespace std;
typedef pair<int ,int > PII;
const int N = 400000;
int a[N],s[N],n,m;
vector<int> alls; //待离散化的数值
vector<PII> add,query;
int find(int x){
int l = 0;
int r = alls.size()-1;
while(l<r){
int mid = l+r >> 1;
if(alls[mid]>=x)r = mid;
else l = mid +1;
}
return r+1;
}
int main(){
cin >> n >> m;
for(int i=1;i<=n;i++){
int x,c;
cin >> x >> c;
alls.push_back(x);
add.push_back({x,c});
}
for(int i=1;i<=m;i++){
int l,r;
cin >> l >> r;
alls.push_back(l);
alls.push_back(r);
query.push_back({l,r});
}
sort(alls.begin(),alls.end());
alls.erase(unique(alls.begin(),alls.end()),alls.end());
for(auto item : add){
int x = find(item.first);
a[x] += item.second;
//cout << x << " : " << a[x] << endl;
}
for(int i=1;i<=alls.size();i++)s[i] = s[i-1] + a[i];
for(auto item : query){
int l = find(item.first);
int r = find(item.second);
cout << s[r] - s[l-1] << endl;
}
}
并查集
(1)朴素并查集:
int p[N]; //存储每个点的祖宗节点
// 返回x的祖宗节点
int find(int x)
{
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
// 初始化,假定节点编号是1~n
for (int i = 1; i <= n; i ++ ) p[i] = i;
// 合并a和b所在的两个集合:
p[find(a)] = find(b);
(2)维护size的并查集:
int p[N], size[N];
//p[]存储每个点的祖宗节点, size[]只有祖宗节点的有意义,表示祖宗节点所在集合中的点的数量
// 返回x的祖宗节点
int find(int x)
{
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
// 初始化,假定节点编号是1~n
for (int i = 1; i <= n; i ++ )
{
p[i] = i;
size[i] = 1;
}
// 合并a和b所在的两个集合:
size[find(b)] += size[find(a)];
p[find(a)] = find(b);
(3)维护到祖宗节点距离的并查集:
int p[N], d[N];
//p[]存储每个点的祖宗节点, d[x]存储x到p[x]的距离
// 返回x的祖宗节点
int find(int x)
{
if (p[x] != x)
{
int u = find(p[x]);
d[x] += d[p[x]];
p[x] = u;
}
return p[x];
}
// 初始化,假定节点编号是1~n
for (int i = 1; i <= n; i ++ )
{
p[i] = i;
d[i] = 0;
}
// 合并a和b所在的两个集合:
p[find(a)] = find(b);
d[find(a)] = distance; // 根据具体问题,初始化find(a)的偏移量
树的重心(深度优先搜索)
#include<bits/stdc++.h>
using namespace std;
const int N = 110000;
vector<int > h[N];
int n,ans = N;
bool f[N];
int dfs(int u){
f[u] = true;
int sum = 1,res = 0;
for(int i=0;i<h[u].size();i++){
if(!f[h[u][i]]){
int s = dfs(h[u][i]);
res = max(res,s);
sum += s;
}
}
res = max(res,n - sum);
ans = min(res,ans);
return sum;
}
int main(){
cin >> n;
for(int i=1;i<=n;i++){
int a,b;
cin >> a >>b;
h[a].push_back(b);
h[b].push_back(a);
}
dfs(1);
cout << ans << endl;
}
树的拓扑排序
#include<bits/stdc++.h>
using namespace std;
const int N = 110000;
vector<int > h[N];
int n,m,d[N],t[N],k=0;
queue<int > q;
bool topsort(){
for(int i=1;i<=n;i++){
if(d[i] == 0){
q.push(i);
t[k++] = i;
}
}
if(k==0)return false;
while(!q.empty()){
int u = q.front();
q.pop();
for(int i=0;i<h[u].size();i++){
int j = h[u][i];
d[j]--;
if(d[j]==0){
q.push(j);
t[k++] = j;
}
}
}
return k == n;
}
int main(){
cin >> n >> m;
for(int i=1;i<=m;i++){
int a,b;
cin >> a >> b;
d[b]++;
h[a].push_back(b);
}
if(topsort()){
for(int i=0;i<k;i++)cout << t[i] << " ";
}else {
cout << -1 << endl;
}
return 0;
}
朴素Dijkstra
#include<bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 510;
int g[N][N],n,m;
int dist[N];
bool st[N];
int dijkstra(){
memset(dist,INF,sizeof dist);
dist[1] = 0;
for(int i=1;i<=n;i++){
int t = -1;
for(int j=1;j<=n;j++){
if(!st[j] && (t==-1||dist[t]>dist[j])){
t = j;
}
}
st[t] = true;
for(int j=1;j<=n;j++){
dist[j] = min(dist[j],dist[t]+g[t][j]);
//cout << dist[j] << " ";
}
//cout <<endl;
}
if(dist[n] == INF)return -1;
return dist[n];
}
int main(){
memset(g,INF,sizeof g);
cin >> n >> m;
for(int i=1;i<=m;i++){
int a,b,c;
cin >> a >> b >> c;
g[a][b] = min(g[a][b],c);
}
cout << dijkstra() << endl;
}
堆优化Dijkstra
#include<bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 110000;
typedef pair<int,int> PII;
vector<PII > g[N];
int n,m,w[N],dist[N];
bool st[N];
int dijkstra(){
memset(dist,INF,sizeof dist);
dist[1] = 0;
priority_queue<PII,vector<PII>,greater<PII>> heap;
heap.push({0,1});
while(heap.size()){
auto t = heap.top();
heap.pop();
int u = t.second,distance = t.first;
if(st[u])continue;
st[u] = true;
for(int i=0;i<g[u].size();i++){
auto j = g[u][i];
if(dist[j.first] > distance + j.second){
dist[j.first] = distance + j.second;
heap.push({dist[j.first],j.first});
}
}
}
if(dist[n] == INF)return -1;
return dist[n];
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
g[a].push_back({b,c});
}
printf("%d",dijkstra());
return 0;
}
差分(将一个前缀和数组差分成原来的数组)
void chaFen(int a[],int l,int r,int c){
a[l]+=c;
a[r+1]-=c;
} //将一个前缀和数组,差分成另一个数组,用于区间修改
快速幂取余
ll powerMod(ll a,ll b,ll mod){
ll ans=1;
a=a%mod;
while(b){
if(b&1)ans=ans*a%mod;
a=a*a%mod;b>>=1;
}
return ans%mod;
}
bellman_ford ( 求一个点到另一个点k条边之内到达 )
#include<bits/stdc++.h>
using namespace std;
const int N = 510 , M = 11000;
const int INF = 0x3f3f3f3f;
int n,m,k;
int dist[N],cp[N];
struct edge {
int a,b,w;
}edges[M];
int bellman_ford(){
memset(dist,INF,sizeof dist);
dist[1] = 0;
for(int i=1;i<=k;i++){
memcpy(cp,dist,sizeof dist); // 记得cpy哦
for(int j=1;j<=m;j++){
int a = edges[j].a ,b = edges[j].b ,w = edges[j].w;
dist[b] = min(dist[b],cp[a] + w);
}
}
if(dist[n] > INF / 2)return -1;
return dist[n];
}
int main(){
cin >> n >> m >> k;
for(int i=1;i<=m;i++){
int a,b,w;
cin >> a >> b >>w;
edges[i] = {a,b,w};
}
int t = bellman_ford();
if(t == -1)cout << "impossible" << endl;
else cout << t << endl;
}
spfa最短路 (判负权)
#include<bits/stdc++.h>
using namespace std;
const int N = 110000;
const int INF = 0x3f3f3f3f;
typedef pair<int ,int > PII;
int n,m,dist[N];
bool st[N];
vector<PII > g[N];
int spfa(){
memset(dist,INF,sizeof dist);
dist[1] = 0;
st[1] = true;
queue<int > q;
q.push(1);
while(q.size()){
int u = q.front();
q.pop();
st[u] = false;
for(int i=0;i<g[u].size();i++){
auto j = g[u][i];
if(dist[j.first] > dist[u] + j.second){
dist[j.first] = dist[u] + j.second;
if(!st[j.first]){
st[j.first] = true;
q.push(j.first);
}
}
}
}
if(dist[n] == INF)return -1;
return dist[n];
}
int main(){
cin >> n >>m;
for(int i=1;i<=m;i++){
int a,b,c;
cin >> a >> b >> c;
g[a].push_back({b,c});
}
int t = spfa();
if(t == -1)cout << "impossible" << endl;
else cout << t << endl;
return 0;
}
Floyd 多源最短路
#include<bits/stdc++.h>
using namespace std;
const int N = 210;
const int INF = 0x3f3f3f3f;
int n,m,t;
int g[N][N];
void Floyd(){
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
if(g[i][k] != INF) // 小小的剪枝一下
for(int j=1;j<=n;j++){
g[i][j] = min(g[i][j],g[i][k] + g[k][j]);
}
}
}
}
int main(){
cin >> n >> m >> t;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i == j)g[i][j] = 0;
else g[i][j] = INF;
}
}
for(int i=1;i<=m;i++){
int a,b,c;
cin >> a >>b >>c;
g[a][b] = min(g[a][b],c);
}
Floyd();
while(t--){
int a,b;
cin >> a >> b;
if(g[a][b] > INF/2)cout << "impossible" << endl;
else cout << g[a][b] << endl;
}
}