【导航页/板子】板子库
yeyou26の板子库
持续更新 纯手敲 板子题已注明 可能存在引用互联网资源 仅供学习交流
にじげんさいこう! ( ‵▽′)ψ
数据结构
图论
网络流
Dinic
int edgeid=1,n,m,ans,cur[N],dis[N],st,ed,head[N];
queue<int> q;
struct edge {int v,w,nxt;} e[M*2];
inline void addedge(int u,int v,int w)
{
edgeid++;
e[edgeid].v=v;
e[edgeid].w=w;
e[edgeid].nxt=head[u];
head[u]=edgeid;
}
bool Bfs()
{
while(!q.empty()) q.pop();
for(int i=1;i<=n;i++)
{
cur[i]=head[i]; //重置当前弧优化
dis[i]=0; //重置距离
}
q.push(st);
dis[st]=1;
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=head[u];i;i=e[i].nxt)
{
int v=e[i].v;
if(e[i].w && !dis[v])
{
dis[v]=dis[u]+1;
if(v==ed) return 1;
q.push(v);
}
}
}
return 0;
}
int Dfs(int u,int rst)
{
if(!rst || u==ed) return rst;
int sum=0;
for(int i=cur[u];i;i=e[i].nxt) //当前弧优化 确保时间复杂度O(n^2 m)
{
int v=e[i].v;
cur[u]=i;
int f;
if(dis[v]==dis[u]+1 && (f=Dfs(v,min(rst,e[i].w))))
{
e[i].w-=f;
e[i^1].w+=f;
sum+=f;
rst-=f;
if(rst==0) break;//余量优化 常数
}
}
if(sum==0) dis[u]=0;//废点优化 常数
return sum;
}
void Dinic() {while(Bfs()) ans+=Dfs(1,INF);}
算法与思想
字符串
字符串最小表示法
int a[2*N];
int n;
void init()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
long long x;
scanf("%d",&x);
a[i]=a[i+n]=x;
}
}
void solve()
{
int i=1,j=2,k=0;
while(i<=n && j<=n)
{
k=0;
while(a[i+k]==a[j+k] && k<n) k++;
if(a[i+k]>a[j+k]) i=i+k+1;
else j=j+k+1;
if(k==n) break;
if(i==j) j++;
}
int ans=min(i,j);
for(int p=1;p<=n;p++)
{
printf("%d ",a[ans+p-1]);
}
}
字符串哈希
const ull p=998244353;
string s;
ull now_hash,v[100005];
int cnt,ans,n;
void get_hash()
{
now_hash=0;
ull now_p=1;
for(int i=1;s[i];i++)
{
now_hash+=s[i]*now_p;
now_p*=p;
}
}
void do_compare()
{
bool flag=0;
for(int i=1;i<=cnt;i++)
{
if(v[i]==now_hash)
{
flag=1;
break;
}
}
if(flag==0)
{
ans++;
v[++cnt]=now_hash;
}
}
void solve()
{
for(int i=1;i<=n;i++)
{
cin>>s;
get_hash();
do_compare();
}
printf("%d",ans);
}
KMP
char p[1000005],s[1000005];
int lenp,lens;
int lst[1000005];
void init()
{
cin>>(s+1)>>(p+1);
lenp=strlen(p+1);
lens=strlen(s+1);
}
void pre_work()
{
lst[1]=0;
for(int i=2,j=0;i<=lenp;i++)
{
while(j && p[j+1]!=p[i]) j=lst[j];
if(p[j+1]==p[i]) j++;
lst[i]=j;
}
}
void kmp()
{
for(int i=1,j=0;i<=lens;i++)
{
while(j && p[j+1]!=s[i]) j=lst[j];
if(p[j+1]==s[i]) j++;
if(j==lenp) printf("%d\n",i-j+1);
}
}
void out_put()
{
for(int i=1;i<=lenp;i++)
{
printf("%d ",lst[i]);
}
}
扩展KMP(Z Function)
char a[N],b[N];
int p[N],z[N];
int lena,lenb;
void init()
{
cin>>(a+1)>>(b+1);
lena=strlen(a+1);
lenb=strlen(b+1);
}
void get_z()
{
z[1]=lenb;
for(int i=2,l=0,r=0;i<=lenb;i++)
{
if(i<=r) z[i]=min(z[i-l+1],r-i+1);
while(b[1+z[i]]==b[i+z[i]]) z[i]++;
if(i+z[i]-1>r) l=i,r=i+z[i]-1;
}
}
void get_p()
{
for(int i=1,l=0,r=0;i<=lena;i++)
{
if(i<=r) p[i]=min(z[i-l+1],r-i+1);
while(i+p[i]<=lena && 1+p[i]<=lenb && a[i+p[i]]==b[1+p[i]]) p[i]++;
if(i+p[i]-1>r) l=i,r=i+p[i]-1;
}
}
马拉车(Manacher)
int d[2*N];
char ipt[N];
char c[2*N];
int n;
void init()
{
cin>>(ipt+1);
c[0]='$';
int k=1;
c[k]='#';
n=strlen(ipt+1);
for(int i=1;i<=n;i++)
{
c[++k]=ipt[i],c[++k]='#';
}
n=k;
}
void Manacher()
{
d[1]=1;
for(int i=2,l,r=1;i<=n;i++)
{
if(i<=r) d[i]=min(d[r-i+l],r-i+1);
while(c[i+d[i]]==c[i-d[i]]) d[i]++;
if(r<i+d[i]-1) r=i+d[i]-1,l=i-d[i]+1;
}
}
Trie字典树
int n,m,t[N][150],idx,cnt[N];
inline int trans(char c) {return c^64;}
void Insert(string s)
{
int p=0;
for(int i=0;s[i];i++)
{
int ch=trans(s[i]);
if(!t[p][ch])
{
t[p][ch]=++idx;
}
p=t[p][ch];
}
cnt[p]++;
}
int Query(string s)
{
int p=0;
for(int i=0;s[i];i++)
{
int ch=trans(s[i]);
if(!t[p][ch])
{
return 0;
}
else
{
p=t[p][ch];
}
}
return cnt[p];
}
01异或树
int n,m,t[N][150],idx,cnt[N];
int trans(char c) {return c^64;}
void Insert(string s)
{
int p=0;
for(int i=0;s[i];i++)
{
int ch=trans(s[i]);
if(!t[p][ch])
{
t[p][ch]=++idx;
}
p=t[p][ch];
}
cnt[p]++;
}
int Query(string s)
{
int p=0;
for(int i=0;s[i];i++)
{
int ch=trans(s[i]);
if(!t[p][ch])
{
return 0;
}
else
{
p=t[p][ch];
}
}
return cnt[p];
}
AC自动机
int t[(int)1e6+6][30],nxt[(int)1e6+5],idx,n;
string mainstring,ss[(int)1e6+6];
void init();
void Addtrie(string s);
void Trie();
queue<int> q;
void Aho_corasick();
int Query(string mainstring);
int main()
{
init();
Trie();
Aho_corasick();
cout<<Query(mainstring);
return 0;
}
//Function Implementation
int Query(string s)
{
int ans=0;
int p=0;
for(int i=0;s[i];i++)
{
int c=s[i]&31;
p=t[p][c];
for(int j=p;cnt[j]!=-1 && j;j=nxt[j])
{
ans+=cnt[j];
cnt[j]=-1;
}
}
return ans;
}
void Addtrie(string s)
{
int p=0;
for(int i=0;s[i];i++)
{
int c=s[i]&31;
if(!t[p][c])
{
t[p][c]=++idx;
}
p=t[p][c];
}
cnt[p]++;
}
void Trie()
{
for(int i=1;i<=n;i++)
{
Addtrie(ss[i]);
}
}
void Aho_corasick()
{
for(int i=1;i<=26;i++)
{
if(t[0][i]) q.push(t[0][i]);
}
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=1;i<=26;i++)
{
int v=t[u][i];
if(v)
{
nxt[v]=t[nxt[u]][i];
q.push(v);
}
else
{
t[u][i]=t[nxt[u]][i];
}
}
}
}
void init()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>ss[i];
}
cin>>mainstring;
}
后缀数组(SA)
//额外数据测试lcp
//input:aabaaaab
//output:sa:4 5 6 1 7 2 8 3
// lcp:0 3 2 3 1 2 0 1
#include<bits/stdc++.h>
using namespace std;
#define w where
const int N = (int)3e6;
int n,m=256;//后缀个数 桶个数(m初始值为值域(应该是吧))
int where[N];//第i个后缀在哪个桶里
int y[N];//临时数组
int c[N];//计数排序的计数数组
int sa[N];//排名为i的后缀
int rk[N];//第i个后缀的排名
int lcp[N];//排名为i的后缀跟排名为i-1的后缀的最长公共前缀的长度
char s[N];
void init();
void get_sa();
void get_lcp();
int main()
{
init();
get_sa();
for(int i=1;i<=n;i++) printf("%d ",sa[i]);
printf("\n");
get_lcp();
for(int i=1;i<=n;i++) printf("%d ",lcp[i]);
return 0;
}
void init()
{
cin>>(s+1);
n=strlen(s+1);
}
//Function Implementation
void get_lcp()
{
for(int i=1;i<=n;i++) rk[sa[i]]=i;
for(int i=1,k=0;i<=n;i++) //枚举第i个后缀
{
if(rk[i]==1) continue;//排名为1的后缀的lcp=0
if(k) k--; //定理:lcp[rk[i]]>=lcp[rk[i-1]]-1;
int j=sa[rk[i]-1]; //从排名上看,i后缀的前临后缀j
while(i+k<=n && j+k<=n && s[i+k]==s[j+k]) k++;//暴力枚举
lcp[rk[i]]=k;
}
}
void get_sa()
{
//第一次计数排序,按第一个字母排
for(int i=1;i<=n;i++) c[w[i]=s[i]]++;
for(int i=1;i<=m;i++) c[i]+=c[i-1];
for(int i=n;i>=1;i--) sa[c[w[i]]--]=i;
for(int k=1;k<=n;k<<=1)
{
//按 后半段字符串 进行计数排序
memset(c,0,sizeof(c));
for(int i=1;i<=n;i++) y[i]=sa[i];
for(int i=1;i<=n;i++) c[w[y[i]+k]]++;
for(int i=1;i<=m;i++) c[i]+=c[i-1];
for(int i=n;i>=1;i--) sa[c[w[y[i]+k]]--]=y[i];
//按 前半段字符串 进行计数排序
memset(c,0,sizeof(c));
for(int i=1;i<=n;i++) y[i]=sa[i];
for(int i=1;i<=n;i++) c[w[y[i]]]++;
for(int i=1;i<=m;i++) c[i]+=c[i-1];
for(int i=n;i>=1;i--) sa[c[w[y[i]]]--]=y[i];
//把排好序的 长度为2k的字符串 放到桶里 并 重新计算桶的个数
m=0;
for(int i=1;i<=n;i++) y[i]=w[i];
for(int i=1;i<=n;i++)
{
if(y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k]) w[sa[i]]=m;
else w[sa[i]]=++m;
}
if(m==n) break; //桶个数跟后缀一样多,说明已经排好了
}
}
后缀自动机(SAM)
//注意:这道题不是纯的后缀自动机,main函数有一点额外处理
#define ll long long
#define N (int(2e6+6))
int fa[N],ch[N][28],len[N],cnt[N],idx=1,np=1;
ll ans;
string s;
vector<int> e[N];
void Addsam(int c);
ll calculate();
void dfs(int u);
int main()
{
freopen("working.in","r",stdin);
freopen("working.out","w",stdout);
cin>>s;
for(int i=0;s[i];i++)
{
Addsam(s[i]&31);
}
for(int i=2;i<=idx;i++)
{
e[fa[i]].push_back(i);
}
dfs(1);
cout<<ans;
return 0;
}
//Function Implementation
void dfs(int u)
{
for(int v : e[u])
{
dfs(v);
cnt[u]+=cnt[v];
}
if(cnt[u]>1) ans=max(ans,(ll)cnt[u]*len[u]);
}
void Addsam(int c)
{
//p回跳指针 np新节点 q链接点 nq分裂链接点
int p=np,np=++idx;
len[np]=len[p]+1;
cnt[np]=1;
for(;p && !ch[p][c];p=fa[p]) ch[p][c]=np;
//case 1 找不到任何出现过(新串后缀)
if(p==0) fa[np]=1;
else
{
int q=ch[p][c];
//case 2 链接点合法,直接连
if(len[q]==len[p]+1) fa[np]=q;
else
{
//case 3 链接点不合法,裂开为nq和q,q负责长度大于len(p)+1的串,nq负责长度小于等于len(p)+1的串
int nq=++idx;
len[nq]=len[p]+1;
fa[nq]=fa[q];fa[q]=nq;fa[np]=nq;
//指向q的转移边指向nq
for(;p && ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
//从q出发的转移边丢给nq一份
memcpy(ch[nq],ch[q],sizeof(ch[q]));
}
}
}
数论/数学/计算几何
世界上最美的GCD
ll Gcd(ll x,ll y){while(y^=x^=y^=x%=y);return x;}
DP
排序
快速排序
int a[N];
void Quicksort(int l,int r)
{
if(l>=r) return ;
int i=l,j=r;
int key=a[l];
while(i<j)
{
while(i<j && a[j]>=key) j--;
a[i]=a[j];
while(i<j && a[i]<=key) i++;
a[j]=a[i];
a[i]=key;
}
Quicksort(l,i-1);
Quicksort(i+1,r);
}
归并排序
int a[N],b[N],cnt;
void Mergesort(int l,int r)
{
if(l>=r) return ;
int mid=(l+r)>>1;
Mergesort(l,mid);
Mergesort(mid+1,r);
int i=l,j=mid+1,k=l;
while(i<=mid && j<=r)
{
if(a[i]<=a[j]) b[k++]=a[i++];
else b[k++]=a[j++],cnt+=mid-i+1;
}
while(i<=mid) b[k++]=a[i++];
while(j<=r) b[k++]=a[j++];
for(int i=l;i<=r;i++) a[i]=b[i];
}
其他
快读/快写
lll Read()
{
bool flag=0;
char ch=getchar();
lll ans=0;
while(!isdigit(ch) && ~ch)
{
flag|=(ch=='-');
ch=getchar();
}
while(isdigit(ch) && ~ch)
{
ans=(ans<<1)+(ans<<3)+(ch^48);
ch=getchar();
}
return flag ? -ans : ans;
}
int _c[100];
void Write(lll x)
{
int i=0;
bool flag=0;
if(x<0) {x=-x;putchar('-');}
if(x==0) putchar('0');
while(x) {_c[++i]=x%10;x/=10;}
while(i) {putchar(_c[i--]^48);}
}

( ‵▽′)ψ*
浙公网安备 33010602011771号