更新
2021-05-10 加入split
2020-12-13 加入技巧章节
2020-06-27 加入Kosaraju
2020-06-26 加入前向星、二分、修复割顶
2020-06-25 加入Trie树、O2优化、万能头部、二进制拆分、拓扑排序
2020-06-25 加入最小生成树、KMP、Dijkstra。更新矩阵快速幂
2020-06-25 更新代码片段,调整文档结构
2020-06-25 重新排版
2017-11-09 NOIP第一次整理上传
前言
自用板子,经测试代码均正确,可以放心食用,源自于17年准备NOIP(当时还不会md😭)。大学程序设计课对板子进行完善。
代码片段
// #pragma GCC optimize(2)
// #include<bits/stdc++.h>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <functional>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <vector>
#define LL long long
using namespace std;
inline int get_num() {
char c;
int f = 1, num = 0;
while ((c = getchar()) == ' ' || c == '\n' || c == '\r')
;
if (c == '-')
f = -1;
else
num = c - '0';
while (isdigit(c = getchar())) num = num * 10 + c - '0';
return num * f;
}
int main() {
// ios::sync_with_stdio(false);
// cout.tie(NULL);
freopen("a.in", "r", stdin);
freopen("a.out", "w", stdout);
fclose(stdin);
fclose(stdout);
return 0;
}
数据结构
线段树
inline void push_up(int p){
tr[p].w=tr[p<<1].w+tr[p<<1|1].w;
}
inline void push_down(int p){
if(!tr[p].lazy) return ;
tr[p<<1].w+=tr[p].lazy*(tr[p<<1].r-tr[p<<1].l+1);
tr[p<<1].lazy+=tr[p].lazy;
tr[p<<1|1].w+=tr[p].lazy*(tr[p<<1|1].r-tr[p<<1|1].l+1);
tr[p<<1|1].lazy+=tr[p].lazy;
tr[p].lazy=0;
}
void build(int p,int l,int r){
tr[p].l=l;tr[p].r=r;
if(l==r){
tr[p].w=get_num();
return ;
}
int mid=(l+r)>>1;
build(p<<1,l,mid);build(p<<1|1,mid+1,r);
push_up(p);
}
void add(int p,int l,int r,LL k){
if(tr[p].l==l&&tr[p].r==r){
tr[p].w+=(r-l+1)*k;
tr[p].lazy+=k;
return ;
}
push_down(p);
int mid=(tr[p].r+tr[p].l)>>1;
if(r<=mid) add(p<<1,l,r,k);
else if(l>mid) add(p<<1|1,l,r,k);
else{
add(p<<1,l,mid,k);add(p<<1|1,mid+1,r,k);
}
push_up(p);
}
LL query(int p,int l,int r){
if(tr[p].l==l&&tr[p].r==r){
return tr[p].w;
}
LL ans=0;
push_down(p);
int mid=(tr[p].r+tr[p].l)>>1;
if(r<=mid) ans=query(p<<1,l,r);
else if(l>mid) ans=query(p<<1|1,l,r);
else{
ans=query(p<<1,l,mid)+query(p<<1|1,mid+1,r);
}
push_up(p);
return ans;
}
int main()
{
int n,m;n=get_num();m=get_num();
build(1,1,n);
int c,x,y;LL k;
for(int i=1;i<=m;i++){
c=get_num();x=get_num();y=get_num();
if(c==1){
k=get_num();
add(1,x,y,k);
}else{
cout<<query(1,x,y)<<'\n';
}
}
return 0;
}
树链剖分
inline void push_up(int p){
tr[p].w=tr[p<<1].w+tr[p<<1|1].w;
}
inline void push_down(int p){
if(!tr[p].lazy) return ;
tr[p<<1].w+=tr[p].lazy*(tr[p<<1].r-tr[p<<1].l+1);
tr[p<<1].lazy+=tr[p].lazy;
tr[p<<1|1].w+=tr[p].lazy*(tr[p<<1|1].r-tr[p<<1|1].l+1);
tr[p<<1|1].lazy+=tr[p].lazy;
tr[p].lazy=0;
}
void build(int p,int l,int r){
tr[p].l=l;tr[p].r=r;
if(l==r){
tr[p].w=w[l];
return ;
}
int mid=(l+r)>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
push_up(p);
}
void add(int p,int l,int r,LL k){
if(tr[p].l==l&&tr[p].r==r)
{
tr[p].w+=(r-l+1)*k;
tr[p].lazy+=k;
return ;
}
push_down(p);
int mid=(tr[p].l+tr[p].r)>>1;
if(r<=mid) add(p<<1,l,r,k);
else if(l>mid) add(p<<1|1,l,r,k);
else{
add(p<<1,l,mid,k);add(p<<1|1,mid+1,r,k);
}
push_up(p);
}
LL query(int p,int l,int r){
if(tr[p].l==l&&tr[p].r==r)
{
return tr[p].w;
}
LL ans=0;
push_down(p);
int mid=(tr[p].l+tr[p].r)>>1;
if(r<=mid) ans=query(p<<1,l,r);
else if(l>mid) ans=query(p<<1|1,l,r);
else{
ans=query(p<<1,l,mid)+query(p<<1|1,mid+1,r);
}
push_up(p);
return ans;
}
void dfs_1(int x){
siz[x]=1;
for(int i=0;i<v[x].size();i++){
if(cur!=f[x]){
f[cur]=x;
deep[cur]=deep[x]+1;
dfs_1(cur);
siz[x]+=siz[cur];
if(siz[son[x]]<siz[cur]) son[x]=cur;
}
}
}
void dfs_2(int x,int p){
id[x]=++tot;w[tot]=d[x];top[x]=p;
if(son[x]) dfs_2(son[x],p);
for(int i=0;i<v[x].size();i++){
if(cur!=f[x]&&cur!=son[x]){
dfs_2(cur,cur);
}
}
}
void modify(int a,int b,int k){
while(top[a]!=top[b]){
if(deep[top[a]]>deep[top[b]]) swap(a,b);
add(1,id[top[b]],id[b],k);
b=f[top[b]];
}if(deep[a]>deep[b]) swap(a,b);
add(1,id[a],id[b],k);
}
LL find(int a,int b){
LL ans=0;
while(top[a]!=top[b]){
if(deep[top[a]]>deep[top[b]]) swap(a,b);
ans+=query(1,id[top[b]],id[b]); ans%=MOD;
b=f[top[b]];
}if(deep[a]>deep[b]) swap(a,b);
ans+=query(1,id[a],id[b]);
return ans%MOD;
}
int main()
{
int n,m,root;
n=get_num();m=get_num();root=get_num();MOD=get_num();
for(int i=1;i<=n;i++) d[i]=get_num();
for(int i=1;i<n;i++){
int a,b;
a=get_num();b=get_num();v[a].push_back(b);
v[b].push_back(a);
}
dfs_1(root);
dfs_2(root,root);
build(1,1,n);
int c,x,y;LL z;
for(int i=1;i<=m;i++){
c=get_num();x=get_num();
if(c==1){
y=get_num();
z=get_num();
modify(x,y,z%MOD);
}else if(c==2)
{
y=get_num();
cout<<find(x,y)<<'\n';
}else if(c==3){
z=get_num();
add(1,id[x],id[x]+siz[x]-1,z%MOD);
}else if(c==4){
cout<<query(1,id[x],id[x]+siz[x]-1)%MOD<<'\n';
}
}
return 0;
}
并查集
int find(int x){
if(f[x]==x) return x;
return f[x]=find(f[x]);
}
初始化 for(int i=1;i<=n;i++) f[i]=i;
树状数组 1
在全局有个 n n n,主函数有个 n n n,读入 n n n的时候,全局相当于 n n n是0。
树状数组 2
void modify(int x,LL p){
for(int i=x;i<=n;i+=lowbit(i)) tr[i]+=p;
//for和tr的i不要写错啊
}
LL query(int x){
LL ans=0;
for(int i=x;i;i-=lowbit(i)) ans+=tr[i];
return ans;
}
-
modify(x,k);modify(y+1,-k);
写的modify(x,k);modify(y+1,k);
-
for(int i=x;i<=n;i+=lowbit(i)) tr[i]+=p;
写的for(int i=x;i<=n;i+=lowbit(i)) tr[x]+=p;
STL堆,priority_queue
priority_queue<int,vector<int>,greater<int> >Q;
int n;n=get_num();
int c,x;
for(int i=1;i<=n;i++){
c=get_num();
if(c==1){
x=get_num();
Q.push(x);
}else if(c==2){
cout<<Q.top()<<'\n';
}else {
Q.pop();
}
}
前向星
inline void add(int x,int y,int w){
v[++p].to=y;
v[p].nxt=fa[x];
v[p].w=w;
fa[x]=p;
}
好久没用了,记一下吧
图论
最近公共祖先
最近公共祖先(LCA)
void dfs(int x){
vis[x]=1;
for(int b=fa[x];b;b=v[b].nxt){
if(!vis[cur])
{
deep[cur]=deep[x]+1;
lca[cur][0]=x;
dfs(cur);
}
}
}
int query(int a,int b)
{
if(deep[a]>deep[b]) swap(a,b);
for(int i=19;i>=0;i--) if(deep[lca[b][i]]>=deep[a]) b=lca[b][i];
if(a==b) return a;
for(int i=19;i>=0;i--){// 是大于等于0不是(int i=19;i;i--)
if(lca[a][i]!=lca[b][i]){
a=lca[a][i];b=lca[b][i];
}
}
return lca[a][0];
}
deep[s]=1;
dfs(s);
for(int j=1;j<=19;j++){
for(int i=1;i<=n;i++){
lca[i][j]=lca[lca[i][j-1]][j-1];
}
}
用vector
TLE 了俩点 还是好好用struct
吧
最近公共祖先(Tarjan)
void tarjan(int x){
vis[x]=1;
f[x]=x;
for(int b=fa[x];b;b=v[b].nxt){
if(!vis[cur]){
tarjan(cur);
f[find(cur)]=x;
}
}
for(int b=faa[x];b;b=qv[b].nxt){
if(vis[qv[b].to]){
qv[b^1].ans=qv[b].ans=find(qv[b].to);
}
}
}
void add(int x,int y){
v[++p].to=y;
v[p].nxt=fa[x];
fa[x]=p;
}
v[++p].to=y
;y
写成了x
最近公共祖先(树剖)
void dfs_1(int x){
siz[x]=1;
for(int b=fa[x];b;b=v[b].nxt){
if(cur!=f[x]){
f[cur]=x;
deep[cur]=deep[x]+1;
dfs_1(cur);
siz[x]+=siz[cur];//忘写了一开始
if(siz[son[x]]<siz[cur]) son[x]=cur;
}
}
}
void dfs_2(int x,int p){
top[x]=p;
if(son[x]) dfs_2(son[x],p);
for(int b=fa[x];b;b=v[b].nxt){
if(cur!=f[x]&&cur!=son[x]){
dfs_2(cur,cur);
}
}
}
int query(int a,int b){
while(top[a]!=top[b]){
if(deep[top[a]]>deep[top[b]]) swap(a,b);
b=f[top[b]];
}
return (deep[a]<=deep[b])? a : b;
}
dfs_1
的时候
dfs_1(cur)
后
忘记写:siz[x]+=siz[cur];
就相当于没有长长的链链了
就跳的很慢很慢了 然后就T了
其实常数是比LCA小的 OK的说
单源最短路径
SPFA
int n,m,s;n=get_num();m=get_num();s=get_num(); for(int i=1;i<=m;i++){ int a,b,c; a=get_num();b=get_num();c=get_num(); add(a,b,c);//注意单项边还是双向边 } for(int i=1;i<=n;i++) d[i]=2147483647; d[s]=0; vis[s]=1;//忘写了一开始 Q.push(s); while(!Q.empty()){ int h=Q.front(); vis[h]=0; Q.pop(); for(int b=fa[h];b;b=v[b].nxt) { if(d[cur]>d[h]+v[b].w) { d[cur]=d[h]+v[b].w; if(!vis[cur]) { vis[cur]=1; Q.push(cur); } } } }
queue
里 vis[h]
进来的时候 没有写vis[h]=0
;
Floyd
int n;n=get_num(); for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ v[i][j]=get_num(); } }for(int i=0;i<=n;i++) v[i][i]=0; for(int k=1;k<=n;k++){ for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ v[i][j]=min(v[i][j],v[i][k]+v[k][j]); } } } int m=get_num(); for(int i=1;i<=m;i++){ int a,b;a=get_num();b=get_num(); cout<<v[a][b]<<'\n'; }
Dijkstra
int main() { int n; n = get_num(); for (int i = 1; i <= n; i++) { v[0][i] = v[i][0] = get_num(); } for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { v[i][j] = get_num(); } } for (int i = 0; i <= n; i++) { vis[i] = 0; d[i] = 1e9; } d[0] = 0; int ans = 0; for (int i = 0; i <= n; i++) { int sum = 1e9, k; for (int i = 0; i <= n; i++) { if (!vis[i] && d[i] < sum) { sum = d[i]; k = i; } } ans += d[k]; vis[k] = 1; for (int i = 0; i <= n; i++) { d[i] = min(d[i], d[k] + v[k][i]); } } cout << ans; return 0;}
堆优化Dijkstra
struct re{
int d,k;
};
struct cmp{
inline bool operator () (re a, re b){
return a.d>b.d;
}
};
priority_queue<re,vector<re>,cmp >Q;
int main()
{
int n,m;
re s;
n=get_num();m=get_num();s.k=get_num();
for(int i=1;i<=m;i++){
int a,b,c;a=get_num();b=get_num();c=get_num();
add(a,b,c);
}
for(int i=1;i<=n;i++) d[i]=2147483647;
d[s.k]=0;re B;s.d=0;
Q.push(s);
while(!Q.empty()){
re h=Q.top();
Q.pop();
if(vis[h.k]) continue;
vis[h.k]=1;
for(int b=fa[h.k];b;b=v[b].nxt){
if(d[cur]>d[h.k]+v[b].w){
d[cur]=d[h.k]+v[b].w;
B.d=d[cur];B.k=v[b].to;
Q.push(B);
}
}
}
for(int i=1;i<=n;i++) cout<<d[i]<<" ";
return 0;
}
负环
void dfs(int x){
if(ans) return ;
vis[x]=1;
for(int b=fa[x];b;b=v[b].nxt){
if(d[cur]>d[x]+v[b].w){
d[cur]=d[x]+v[b].w;
if(vis[cur])
{
ans=1;
break;
}
dfs(cur);
}
}
vis[x]=0;
}
while(t)
{
t--;int n,m;
memset(vis,0,sizeof(vis));
memset(d,0,sizeof(d));
memset(fa,0,sizeof(fa));p=0;
n=get_num();m=get_num();
for(int i=1;i<=m;i++){
int a,b,w;
a=get_num();b=get_num();w=get_num();
add(a,b,w);
if(w>=0) add(b,a,w);
}
ans=0;
for(int i=1;i<=n;i++){
dfs(i);
if(ans) break;
}
if(ans) cout<<"YE5\n";
else cout<<"N0\n";
}
最小生成树
Kruskal
const int MAXN = 3e2 + 7;int par[MAXN];struct re { int x, y, w; bool operator<(const re& a) const { return w < a.w; }} v[MAXN * MAXN];int find(int x) { return par[x] == x ? x : par[x] = find(par[x]); }int main() { int n; cin >> n; int cnt = 1; for (int i = 1; i <= n; i++) { v[cnt].x = 0; v[cnt].y = i; cin >> v[cnt].w; ++cnt; } for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { int w = get_num(); if (i == j) continue; v[cnt].x = i; v[cnt].y = j; v[cnt].w = w; cnt++; } } sort(v + 1, v + cnt); int ans = 0, sum = 0; for (int i = 1; i <= n; i++) par[i] = i; for (int i = 1; i < cnt; i++) { if (sum == n) break; if (find(v[i].x) != find(v[i].y)) { ans += v[i].w; par[find(v[i].x)] = find(v[i].y); sum++; } } cout << ans; return 0;}
Prim
const int MAXN = 3e2 + 7;int v[MAXN][MAXN], vis[MAXN], d[MAXN];int main() { int n; n = get_num(); for (int i = 1; i <= n; i++) { v[0][i] = v[i][0] = get_num(); } for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { v[i][j] = get_num(); } } for (int i = 0; i <= n; i++) { vis[i] = 0; d[i] = 1e9; } d[0] = 0; int ans = 0; for (int i = 0; i <= n; i++) { int sum = 1e9, k; for (int i = 0; i <= n; i++) { if (!vis[i] && d[i] < sum) { sum = d[i]; k = i; } } ans += d[k]; vis[k] = 1; for (int i = 0; i <= n; i++) { d[i] = min(d[i], v[k][i]); } } cout << ans; return 0;}
堆优化的Prim
const int MAXN = 3e2 + 7;int v[MAXN][MAXN], vis[MAXN], d[MAXN];struct re { int d, w; bool operator<(const re &a) const { return w > a.w; }};priority_queue<re> Q;int main() { int n; n = get_num(); for (int i = 1; i <= n; i++) { v[0][i] = v[i][0] = get_num(); } for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { v[i][j] = get_num(); } } for (int i = 0; i <= n; i++) { vis[i] = 0; d[i] = 1e9; } d[0] = 0; Q.push({0, 0}); int ans = 0; while (!Q.empty()) { re h = Q.top(); Q.pop(); if (vis[h.d]) continue; vis[h.d] = 1; ans += h.w; for (int i = 0; i <= n; i++) { if (d[i] > v[h.d][i]) { d[i] = v[h.d][i]; Q.push({i, d[i]}); } } } cout << ans; return 0;}
二分图匹配 再打一遍
int dfs(int x){ for(int i=0;i<v[x].size();i++){ if(!vis[cur]) { vis[cur]=1; if(!match[cur]||dfs(match[cur])) { match[cur]=x; match[x]=cur; return 1; } } } return 0;}int n;int query(){ int ans=0; for(int i=1;i<=n;i++){ if(!match[i]){ memset(vis,0,sizeof(vis)); if(dfs(i)) ans++; } } return ans;}int main(){ int m,e;n=get_num();m=get_num();e=get_num(); for(int i=1;i<=e;i++){ int a,b;a=get_num();b=get_num(); if(b<=m) v[a].push_back(b+n); } cout<<query(); return 0;}
强连通分量
缩点 再打一遍
void tarjan(int x){ my_s.push(x);in_s[x]=1;//注意不要忘了 dfn[x]=low[x]=++tot; for(int b=fa[x];b;b=v[b].nxt){ if(!dfn[cur]){ tarjan(cur); low[x]=min(low[x],low[cur]); } else if(in_s[cur]) low[x]=min(low[x],dfn[cur]); } if(low[x]==dfn[x]) { ++bcnt; while(my_s.top()!=x){ fd[my_s.top()]=bcnt;d[bcnt]+=w[my_s.top()];in_s[my_s.top()]=0;my_s.pop(); } d[bcnt]+=w[my_s.top()];fd[my_s.top()]=bcnt;in_s[my_s.top()]=0;my_s.pop(); }}void build(){ for(int i=1;i<=n;i++){ for(int b=fa[i];b;b=v[b].nxt) { if(fd[i]!=fd[cur]) { qv[fd[i]].push_back(fd[cur]); } } }}int dfs(int x){ if(dp[x]) return dp[x]; for(int i=0;i<qv[x].size();i++){ dp[x]=max(dp[x],dfs(qv[x][i])); } dp[x]+=d[x]; return dp[x];}
割顶(割点)
void tarjan(int x){ dfn[x]=low[x]=++tot; int rt=0; for(int b=fa[x];b;b=v[b].nxt){ if(!dfn[cur]){ rt++; f[cur]=f[x]; tarjan(cur); low[x]=min(low[x],low[cur]); if(low[cur]>=dfn[x]&&f[x]!=x&&!vis[x]) vis[x]=1,ans++; //重要 }else low[x]=min(low[x],dfn[cur]); } if(f[x]==x&&rt>=2) ans++,vis[x]=1;}
Kosaraju
int n, c[N], dfn[N], vis[N], dcnt, scnt;
vector<int> G1[N], G2[N]; // G1 原图,G2 反向图
void dfs1(int x) {
vis[x] = 1;
for (auto y : G1[x]) {
if (!vis[y]) dfs1(y);
}
dfn[++dcnt] = x;
}
void dfs2(int x) {
c[x] = scnt;
for (auto y : G2[x]) {
if (!c[y]) dfs2(y);
}
}
void kosaraju() {
dcnt = scnt = 0;
memset(c, 0, sizeof(c));
memset(vis, 0, sizeof(vis));
for (int i = 1; i <= n; i++) {
if (!vis[i]) dfs1(i);
}
for (int i = n; i >= 1; i--) {
if (!c[dfn[i]]) ++scnt, dfs2(dfs[i]);
}
}
- 前序序列
- 后序序列
- 逆逆序序列(后序序列的逆序,原图缩点后的的拓扑顺序)
拓扑排序
bool topoSort(int n) { queue<int> Q; for (int i = 0; i < n; i++) { if (in_deg[i] == 0) Q.push(i); } vector<int> ans; while (!Q.empty()) { int u = Q.front(); Q.pop(); ans.push_back(u); for (auto& i : v[u]) { if (--in_deg[i] == 0) Q.push(i); } } if (ans.size() == n) { for (auto& i : ans) { cout << i << " "; } cout << endl; } else return false;}
树上差分
LL fast_pow(LL a,LL p,LL k){ LL ans=(a==0)?0:1; a%=k; for(;p;p>>=1,a=(a*a)%k) { if(p&1) ans=(ans*a)%k; }return ans;}int main(){ LL n,l,r;cin>>n>>l>>r; for(int i=1;i<=n;i++){ v[i].m=get_num();v[i].a=get_num(); } LL M=1; for(int i=1;i<=n;i++) M*=v[i].m; for(int i=1;i<=n;i++){ v[i].M=M/v[i].m; v[i].k=fast_pow(v[i].M,v[i].m-2,v[i].m); } LL ans=0; for(int i=1;i<=n;i++) ans=(ans+v[i].a*v[i].M*v[i].k)%M; //cout<<ans; LL anss=0; if(r>=ans) anss=(r-ans)/M+1; if(l-1>=ans) anss-=(l-ans-1)/M+1; if(anss==0) cout<<0<<'\n'<<0; else{ cout<<anss<<'\n'; if(l-1>=ans){ cout<<((l-1-ans)/M+1)*M+ans; }else cout<<ans; } return 0;}
最大流量
const int maxn=50010;struct re{ int fd,to,nxt,ans;}qv[maxn<<2];vector<int> v[maxn];int p=1,fa[maxn],vis[maxn],d[maxn],f[maxn],fath[maxn];int n,k;inline void add(int x,int y){ qv[++p].to=y; qv[p].nxt=fa[x]; qv[p].fd=x; fa[x]=p;}inline int get_num(){ char c; int f=1,num=0; while((c=getchar())==' '||c=='\n'||c=='\r'); if(c=='-') f=-1; else num=c-'0'; while(isdigit(c=getchar())) num=num*10+c-'0'; return num*f;}int find(int x){ if(f[x]==x) return x; return f[x]=find(f[x]);}void tarjan(int x){ vis[x]=1; f[x]=x; for(int i=0;i<v[x].size();i++){ if(!vis[cur]){ fath[cur]=x; tarjan(cur); f[find(cur)]=x; } } for(int b=fa[x];b;b=qv[b].nxt){ if(vis[qv[b].to]){ qv[b].ans=qv[b^1].ans=find(qv[b].to); } }}void dfs(int x){ vis[x]=1; for(int i=0;i<v[x].size();i++){ if(!vis[cur]){ dfs(cur); d[x]+=d[cur]; } }}int query(){ for(int i=2;i<=p;i+=2){ ++d[qv[i].fd];++d[qv[i].to];--d[qv[i].ans]; --d[fath[qv[i].ans]]; } memset(vis,0,sizeof(vis)); dfs(1); int ans=0; for(int i=1;i<=n;i++){ ans=max(ans,d[i]); }return ans;}int main(){ n=get_num();k=get_num(); for(int i=1;i<n;i++){ int a,b;a=get_num();b=get_num(); v[a].push_back(b);v[b].push_back(a); } for(int i=1;i<=k;i++){ int a,b;a=get_num();b=get_num(); add(a,b);add(b,a); } for(int i=1;i<=n;i++){ if(!vis[i]) tarjan(i); } cout<<query(); return 0;}
算法
二分法
int find(int x) {
int l = 1, r = n, ans = -1;
while (l <= r) {
int mid = (l + r) >> 1;
if (a[mid] >= x) {
ans = mid;
r = mid - 1;
} else
l = mid + 1;
}
return ans;
}
int find(int x) {
int l = 1, r = n;
while (l <= r) {
int mid = (l + r) >> 1;
if (a[mid] >= x) {
r = mid - 1;
} else
l = mid + 1;
}
return l;
}
三分法
int n;
double v[20];
double eps = 1e-7;
double find(double x) { //find类型不要写错
double ans = v[n + 1];
double p = 1;
for (int i = n; i; i--) {
p *= x;
ans += v[i] * p;
}
return ans;
}
int main() {
double l, r, mid, midd;
cin >> n >> l >> r;
for (int i = 1; i <= n + 1; i++) cin >> v[i];
while (l + eps <= r) {
mid = (l + r) / 2;
midd = (l + mid) / 2;
if (find(midd) < find(mid))
l = midd;
else
r = mid;
}
printf("%.5lf", l);
return 0;
}
double
类型用的get_num()
读进去了
其实应该用cin>>
能过样例也是奇迹
LCS(最长公共子序列) O ( n l o g n ) O(nlogn) O(nlogn)做法
int n;n=get_num();
for(int i=1;i<=n;i++) f[get_num()]=i;
for(int i=1;i<=n;i++){
int c=f[get_num()];
if(c>dp[len]) dp[++len]=c;
else{
int l=1,r=len,mid;
while(l<=r){
mid=(l+r)>>1;
if(dp[mid]>c) r=mid-1;
else l=mid+1;
}dp[l]=c;
}
}
cout<<len;
二进制拆分
void solv(int n) {
cnt = 0;
for (int i = 1; i <= n; i++) {
int w, k;
cin >> k >> w;
for (int j = 1; j <= k; j <<= 1) {
cnt++;
v[cnt] = j * w;
k -= j;
}
if (k) {
cnt++;
v[cnt] = k * w;
}
}
}
数论
快速幂
LL fast_pow(LL a, LL p, LL k) {
LL ans = (a == 0) ? 0 : 1; //注意是a不是p a%=k;
for (; p; p >>= 1, a = (a * a) % k) {
if (p & 1) ans = (ans * a) % k;
}
return ans;
}
gcd
int gcd(int a, int b) {
if (b == 0) return a;
return gcd(b, a % b);
}
exgcd 同余方程
void exgcd(LL a, LL b, LL &x, LL &y) {
if (b == 0) {
x = 1, y = 0;
return;
}
exgcd(b, a % b, x, y);
LL x2 = x, y2 = y;
x = y2;
y = x2 - (a / b) * y2; //手推即可
}
线性筛素数
{
int n, m;
n = get_num();
m = get_num();
for (int i = 2; i <= n; i++) {
if (!vis[i]) pri[++cnt] = i;
for (int j = 1; j <= cnt && pri[j] * i <= n; j++) {
vis[i * pri[j]] = 1; //注意谁%谁 后者%不动
if (i % pri[j] == 0) break;
}
}
vis[1] = 1; //注意1首先啥都不是 其次他不是素数 for(int i=1;i<=m;i++){ if(vis[get_num()]) cout<<"No\n";
else cout << "Yes\n";
}
没有考虑vis[1]=1
的情况 详情看日记
矩阵快速幂
const int N = 3;
LL p = 10007;
struct Matrix {
LL x[N][N];
Matrix operator*(const Matrix &t) const {
Matrix ret;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
ret.x[i][j] = 0;
for (int k = 0; k < N; ++k) {
ret.x[i][j] += (x[i][k] * t.x[k][j]) % p;
ret.x[i][j] %= p;
}
}
}
return ret;
} // 为了防止奇怪的错误,最好写上构造函数
Matrix() { memset(x, 0, sizeof(x)); }
Matrix(const Matrix &t) { memcpy(x, t.x, sizeof(x)); }
};
Matrix quick_pow(Matrix a, LL x) {
Matrix ret;
for (int i = 0; i < N; i++) {
ret.x[i][i] = 1;
}
while (x) {
if (x & 1) ret = ret * a;
a = a * a;
x >>= 1;
}
return ret;
}
int main() {
int T;
cin >> T;
while (T--) {
LL n;
cin >> n;
Matrix a;
a.x[0][0] = a.x[1][1] = a.x[2][0] = a.x[2][1] = a.x[2][2] = 2;
a.x[0][2] = a.x[1][2] = 1;
Matrix P = quick_pow(a, n);
cout << P.x[0][0] << '\n';
}
return 0;
}
fast_pow
里面p>>=1
写的p>>1
get_num()
没改LL
乘法逆元
{
LL n, p;
cin >> n >> p;
inv[1] = 1 % p;
cout << inv[1] << '\n';
for (int i = 2; i <= n; i++) {
inv[i] = (p - p / i) * inv[p % i] % p; //由p%i+(p/i)*i=p开始
cout << inv[i] << '\n';
}
}
字符串
KMP
void getNext(const string &p) {
int len = p.size();
nxt[0] = 0;
for (int i = 1, j = 0; i < len; ++i) {
while (j && p[i] != p[j]) j = nxt[j - 1];
if (p[i] == p[j]) j++;
nxt[i] = j;
}
}
int KMP(const string &s, const string &p) {
int ans = 0;
getNext(p);
int len1 = s.size(), len2 = p.size();
for (int i = 0, j = 0; i < len1; ++i) {
while (j && s[i] != p[j]) j = nxt[j - 1];
if (s[i] == p[j]) j++;
if (j == len2) {
ans++;
j = nxt[j - 1];
}
}
return ans;
}
Trie
struct Trie {
static const int N = 1e6 + 7, charset = 2;
int tot, root, child[N][charset], flag[N];
Trie() { clear(); }
void clear() {
memset(child, -1, sizeof(child));
memset(flag, 0, sizeof(flag));
root = tot = 0;
}
void insert(const string &s) {
int now = root;
for (int i = 0; i < (int)s.size(); i++) {
int x = s[i] - 'a';
if (child[now][x] == -1) {
child[now][x] = ++tot;
flag[now] = 0;
}
now = child[now][x];
}
flag[now] = 1;
}
// 查询字典树中是否存在某个完整的字符串是s的前缀
bool query(const string &s) {
int now = root;
for (int i = 0; i < (int)s.size(); i++) {
int x = s[i] - 'a';
if (child[now][x] == -1) return false;
if (flag[now]) return true;
now = child[now][x];
}
return false;
}
};
STL
Map
技巧
MAP初始化
// 方法一
map<char, int> M1({{'Q', 0}, {'W', 1}, {'E', 2}, {'R', 3}});
// 方法二:采用C++11新特性:
// C++11 还把初始化列表的概念绑定到了类型上,并将其称之为 std::initializer_list,允许构造函数或其他函数像参数一样使用初始化列表,
map<char, int> M2{{'Q', 0}, {'W', 1}, {'E', 2}, {'R', 3}};
split
vector<string> split(const string& s, char c) { //分隔文件名
vector<string> res;
string tmp;
stringstream ss(s);
while (getline(ss, tmp, c)) res.push_back(tmp); //res保存整体
return res;
}
// std::vector<std::string> split(const std::string& line, char c) {
// std::stringstream stm(line);
// std::vector<std::string> ans;
// std::string tmp;
// while (std::getline(stm, tmp, c)) ans.push_back(tmp);
// return ans;
// }