发呆用

Graph

缩点

点击查看代码
vector<int>e[N];
int dfn[N],low[N],tim;
int st[N],top;bool in[N];
int bl[N],scc;
void tarjan(int u){
	dfn[u]=low[u]=++tim;
	st[++top]=u,in[u]=true;
	for(int v:e[u]){
		if(!dfn[v])tarjan(v),low[u]=min(low[u],low[v]);
		else if(in[v])low[u]=min(low[u],dfn[v]);
	}
	if(dfn[u]==low[u]){
		scc++;
		for(int x=0;x!=u;)
			x=st[top--],in[x]=false,bl[x]=scc;
	}
}

2-SAT 差不多。


割点

点击查看代码
vector<int>e[N];
int dfn[N],low[N],tim;
bool cut[N];
void tarjan(int u,int rt){
	dfn[u]=low[u]=++tim;
	int fl=0;
	for(int v:e[u]){
		if(!dfn[v]){
			tarjan(v,rt),low[u]=min(low[u],low[v]);
			if(low[v]>=dfn[u])fl++;
		}
		else low[u]=min(low[u],dfn[v]);
	}
	if(fl>1||(fl&&u!=rt))cut[u]=true;
}

点双

点击查看代码
int dfn[N],low[N],tim;
int st[N],top;
vector<int>s[N];int scc;
void tarjan(int u,int E){
	dfn[u]=low[u]=++tim;
	if(!E&&!head[u]){
		s[++scc].push_back(u);
		return;
	}
	st[++top]=u;
	for(int i=head[u],v;i;i=nxt[i]){
		if(i==(E^1))continue;
		if(!dfn[v=ver[i]]){
			tarjan(v,i),low[u]=min(low[u],low[v]);
			if(low[v]>=dfn[u]){
				scc++;
				for(int x=0;x!=v;)
					x=st[top--],s[scc].push_back(x);
				s[scc].push_back(u);
			}
		}
		else low[u]=min(low[u],dfn[v]);
	}
}

边双

点击查看代码
int dfn[N],low[N],tim;bool bri[M<<1];
vector<int>s[N];int scc;
void tarjan(int u,int E){
	dfn[u]=low[u]=++tim;
	for(int i=head[u],v;i;i=nxt[i]){
		if(i==(E^1))continue;
		if(!dfn[v=ver[i]]){
			tarjan(v,i),low[u]=min(low[u],low[v]);
			if(low[v]>dfn[u])bri[i]=bri[i^1]=true;
		}
		else low[u]=min(low[u],dfn[v]);
	}
}
int bl[N];
void dfs(int u){
	bl[u]=scc,s[scc].push_back(u);
	for(int i=head[u],v;i;i=nxt[i]){
		if(bl[v=ver[i]]||bri[i])continue;
		dfs(v);
	}
}

欧拉路径

点击查看代码
int cur[N];
stack<int>q;
void dfs(int x){
	for(int i=cur[x];i<e[x].size();i=cur[x])
		cur[x]++,dfs(e[x][i]);
	q.push(x);
}
Main
bool flag=true;
for(int i=1;i<=n;i++){
	if(in[i]==out[i])continue;
	flag=false;
	if(out[i]==in[i]+1)c1++,st=i;
	else if(in[i]==out[i]+1)c2++;
	else printf("No\n"),exit(0);
}
if(!flag&&(c1!=1||c2!=1))
	printf("No\n"),exit(0);
dfs(st);
while(!q.empty())
	printf("%d ",q.top()),q.pop();
printf("\n");

SPFA

点击查看代码
int n,m,cnt[N];
int dis[N];bool in[N];
vector<pii>e[N];
bool spfa(){
	memset(dis,0x3f,sizeof(dis));
	queue<int>q;
	dis[1]=0,q.push(1);
	while(!q.empty()){
		int u=q.front();q.pop();
		cnt[u]++,in[u]=false;
		for(pii E:e[u]){
			if(dis[E.fi]>dis[u]+E.se){
				dis[E.fi]=dis[u]+E.se;
				if(!in[E.fi]){
					q.push(E.fi);
					if(++cnt[E.fi]>=n)return true;
				}
			}
		}
	}
	return false;
}

匈牙利

Match
bool dfs(int x){
	for(int y:e[x])
		if(!vis[y]){
			vis[y]=true;
			if(!match[y]||dfs(match[y]))
				return match[y]=x,true;
		}
	return false;
}
Main
for(int i=1;i<=n;i++){
	memset(vis,0,sizeof(vis));
	ans+=dfs(i);
}

先染色然后遍历左部点。


最大流

Flow
int head[N],ver[M],nxt[M];ll edge[M];int tot;
void add(int u,int v,ll w){
	nxt[++tot]=head[u],ver[tot]=v,edge[tot]=w,head[u]=tot;
	nxt[++tot]=head[v],ver[tot]=u,edge[tot]=0,head[v]=tot;
}
int d[N],now[N];ll flow;
bool bfs(){
	memset(d,0,sizeof(d));
	queue<int>q;
	q.push(S),d[S]=1,now[S]=head[S];
	while(!q.empty()){
		int x=q.front();q.pop();
		for(int i=head[x],y;i;i=nxt[i]){
			if(edge[i]&&!d[y=ver[i]]){
				now[y]=head[y],d[y]=d[x]+1,q.push(y);
				if(y==T)return true;
			}
		}
	}
	return false;
}
ll dinic(int x,ll flow){
	if(x==T)return flow;
	ll ret=0;
	for(int i=now[x],y;i&&flow;i=nxt[i]){
		now[x]=i,y=ver[i];
		if(edge[i]&&d[y]==d[x]+1){
			ll k=dinic(y,min(flow,edge[i]));
			if(!k)d[y]=0;
			edge[i]-=k,edge[i^1]+=k;
			ret+=k,flow-=k;
		}
	}
	return ret;
}
Main
while(bfs()){
	while(flow=dinic(S,inf))
		ans+=flow;
}

费用流

点击查看代码
int n,m,S,T;
int head[N],ver[M],nxt[M],w[M],c[M],tot;
void add(int u,int v,int flow,int cost){
	nxt[++tot]=head[u],ver[tot]=v,w[tot]=flow,c[tot]=cost,head[u]=tot;
	nxt[++tot]=head[v],ver[tot]=u,w[tot]=0,c[tot]=-cost,head[v]=tot;
}
int dis[N],incf[N],pre[N];bool vis[N];
int MX,mf,mc;
bool SPFA(){
	queue<int>q;
	memset(dis,0x3f,sizeof(dis)),MX=dis[0];
	memset(vis,0,sizeof(vis));
	q.push(S),dis[S]=0,vis[S]=true,incf[S]=MX;
	while(!q.empty()){
		int u=q.front();q.pop(),vis[u]=false;
		for(int i=head[u],v;i;i=nxt[i]){
			if(!w[i])continue;
			if(dis[v=ver[i]]>dis[u]+c[i]){
				dis[v]=dis[u]+c[i];
				incf[v]=min(incf[u],w[i]),pre[v]=i;
				if(!vis[v])vis[v]=true,q.push(v);
			}
		}
	}
	return dis[T]!=MX;
}
void MCMF(){
	while(SPFA()){
		mf+=incf[T],mc+=dis[T]*incf[T];
		for(int x=T,i=pre[x];x!=S;){
			w[i]-=incf[T],w[i^1]+=incf[T];
			x=ver[i^1],i=pre[x];
		}
	}
}

String

KMP

点击查看代码
int kmp[N];
void KMP(char *s,int len){
	for(int i=2,j=0;i<=len;i++){
		while(j&&s[i]!=s[j+1])j=kmp[j];
		if(s[i]==s[j+1])j++;
		kmp[i]=j;
	}
}
int len;char s[N];
int main(){
	scanf("%s",s+1),len=strlen(s+1);
	KMP(s,len);
	for(int i=1;i<=len;i++)
		printf("%d ",kmp[i]);
	
    return 0;
}

manacher

点击查看代码
int n;char t[N],s[N<<1];
int len[N<<1];
void getstr(){
	int m=0;s[m++]='@';
	for(int i=1;i<=n;i++)
		s[m++]='#',s[m++]=t[i];
	s[m++]='#',s[n=m]=0;
}
int manacher(){
	int mx=0,id,mxlen=0;
	for(int i=1;i<n;i++){
		if(mx>i)len[i]=min(mx-i,len[2*id-i]);
		else len[i]=1;
		while(s[i+len[i]]==s[i-len[i]])len[i]++;
		if(len[i]+i>mx){
			mx=len[i]+i,id=i;
			mxlen=max(mxlen,len[i]);
		}
	}
	return mxlen-1;
}

SAM

看看板子。

SAM
struct state{
	int len,link,siz;
	int nxt[26];
	#define len(x) st[x].len
	#define link(x) st[x].link
	#define siz(x) st[x].siz
	#define nxt(x,c) st[x].nxt[c]
}st[N];
int node,last;
void init(){
	st[1].len=0,st[1].link=0;
	node=last=1;
}
void extend(int c){
	int cur=++node;
	len(cur)=len(last)+1,siz(cur)=1;
	int p=last;
	while(p&&!nxt(p,c))
		nxt(p,c)=cur,p=link(p);
	if(!p)link(cur)=1;
	else{
		int q=nxt(p,c);
		if(len(p)+1==len(q))link(cur)=q;
		else{
			int tp=++node;
			st[tp]=st[q],siz(tp)=0,len(tp)=len(p)+1;
			while(p&&nxt(p,c)==q)
				nxt(p,c)=tp,p=link(p);
			link(q)=link(cur)=tp;
		}
	}
	last=cur;
}
拓扑
scanf("%s",s+1),n=strlen(s+1);
init();
for(int i=1;i<=n;i++)extend(s[i]-'a');
for(int i=1;i<=node;i++)t[len(i)]++;
for(int i=1;i<=node;i++)t[i]+=t[i-1];
for(int i=1;i<=node;i++)A[t[len(i)]--]=i;
for(int i=node;i>1;i--){
	int now=A[i];
	if(link(now))siz(link(now))+=siz(now);
	if(siz(now)>1)ans=max(ans,1ll*len(now)*siz(now));
}

Math

原根

\(m\) 有原根:\(m=2,4,p^k,2p^k\)

原根判定定理:\(\forall p\in \mathrm{P},p\mid \varphi(m)\)\(g^{\frac{\varphi(m)}{p}}\ne 1\pmod m\)

Pollard-Rho

点击查看代码
mt19937 rd(233);
ll read(){
    ll x=0;
    char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))x=x*10+(ch^48),ch=getchar();
    return x;
}
ll qmul(ll k,ll b,ll p){
    return (__int128)k*b%p;
}
ll qpow(ll k,ll b,ll p){
	ll val=1;k%=p;
	while(b){
		if(b&1)val=qmul(val,k,p);
		k=qmul(k,k,p),b>>=1;
	}
	return val;
}
ll T,n,ans;
bool check(ll a,ll n){
	ll u=n-1,t=0;
	while(!(u&1))u>>=1,t++;
	ll x=qpow(a,u,n);
	if(x==1)return false;
	for(ll i=1,tmp;i<=t;i++,x=tmp){
        tmp=qmul(x,x,n);
		if(x!=1&&x!=n-1&&tmp==1)
			return true;
	}
	return x!=1;
}
bool Miller_Rabin(ll n){
	if(n==2)return true;
	if(n<2||!(n&1))return false;
	for(ll i=1;i<=Test;i++){
		if(check(rd()%(n-1)+1,n))
			return false;
	}
	return true;
}
ll f(ll x,ll c,ll n){
    return (qmul(x,x,n)+c)%n;
}
ll Pollard_Rho(ll n){
	if(!(n&1))return 2;
    ll x=rd()%(n-1)+1,y=x,c=rd()%(n-1)+1,ret;
    for(ll i=1;;i<<=1,y=x,ret=1){
        for(ll j=1;j<=i;j++){
	        x=f(x,c,n);
           	ret=qmul(ret,abs(x-y),n);
            if(!(j&127)){
                ll d=__gcd(ret,n);
                if(d>1)return d;
    		}
        }
        ll d=__gcd(ret,n);
        if(d>1)return d;
    }
}
---

Burnside

\[L=\frac{1}{|G|}\Big(c_1(a_1)+c_1(a_2)+\cdots+c_1(a_g)\Big) \]

\(c_1(a_k)\) 理解为不变方案数即可。


BSGS

点击查看代码
ll BSGS(ll a,ll b,ll p){
	map<ll,ll>hs;
	hs.clear(),b%=p;
	ll B=sqrt(p)+1;
	for(ll i=0,cur=b;i<B;i++)
		hs[cur]=i,(cur*=a)%=p;
	a=qpow(a,B,p);
	if(!a)return !b?1:-1;
	for(ll i=1,cur=1;i<=B;i++){
		(cur*=a)%=p;
		ll j=hs.find(cur)==hs.end()?-1:hs[cur];
		if(j>=0&&i*B-j>=0)return i*B-j;
	}
	return -1;
}

CRT

\(M=\prod m_i\)\(M_i=\dfrac{M}{m_i}\)\(t_i\equiv M_i^{-1}\pmod {m_i}\)

一解为 \(\displaystyle x=\sum_{i=1}^{k}a_iM_it_i\),任意解 \(x_0=x+k\cdot M\)


FWT

点击查看代码
void OR(int *a,int x){
	for(int p=2,k=1;p<=lim;p<<=1,k<<=1)
		for(int i=0;i<lim;i+=p)
			for(int j=0;j<k;j++)
				(a[i+j+k]+=1ll*x*a[i+j]%P)%=P;
}
void AND(int *a,int x){
	for(int p=2,k=1;p<=lim;p<<=1,k<<=1)
		for(int i=0;i<lim;i+=p)
			for(int j=0;j<k;j++)
				(a[i+j]+=1ll*x*a[i+j+k]%P)%=P;
}
void XOR(int *a,int x){
	for(int p=2,k=1;p<=lim;p<<=1,k<<=1)
		for(int i=0;i<lim;i+=p)
			for(int j=0;j<k;j++){
				(a[i+j]+=a[i+j+k])%=P;
				a[i+j+k]=((a[i+j]-a[i+j+k]*2)%P+P)%P;
				a[i+j]=1ll*a[i+j]*x%P,a[i+j+k]=1ll*a[i+j+k]*x%P;
			}
}

子集卷积

一个观察是 \(|i|+|j|=|i\cup j|\)

点击查看代码
void OR(int *a,int x){
	for(int p=2,k=1;p<=lim;p<<=1,k<<=1)
		for(int i=0;i<lim;i+=p)
			for(int j=0;j<k;j++)
				(a[i+j+k]+=1ll*a[i+j]*x%P)%=P;
}
int f[N][M],g[N][M],h[N][M];
int main(){
	n=read(),lim=(1<<n);
	for(int i=0;i<lim;i++)f[pcnt(i)][i]=read();
	for(int i=0;i<lim;i++)g[pcnt(i)][i]=read();
	for(int i=0;i<=n;i++)
		OR(f[i],1),OR(g[i],1);
	for(int i=0;i<=n;i++)
		for(int j=0;j+i<=n;j++)
			for(int s=0;s<(1<<n);s++)
				(h[i+j][s]+=1ll*f[i][s]*g[j][s]%P)%=P;
	for(int i=0;i<=n;i++)
		OR(h[i],P-1);
	for(int i=0;i<lim-1;i++)
		printf("%d ",h[pcnt(i)][i]);
	printf("%d\n",h[n][lim-1]);
	
	return 0;
}

多项式

别惦记你那多项式了。

点击查看代码
int qpow(int k,int b){
	int ret=1;
	while(b){
		if(b&1)ret=1ll*ret*k%P;
		k=1ll*k*k%P,b>>=1;
	}
	return ret;
}
int A[N],a2[N],lnb[N];
int lim,r[N],gn,tp,inv;
int iv[N];
void init_iv(int n){
	iv[1]=1;
	for(int i=2;i<=n;i++)
		iv[i]=1ll*(P-P/i)*iv[P%i]%P;
}
void init_r(int lim){
	for(int i=0;i<lim;i++)
        r[i]=(r[i>>1]>>1)+(i&1)*(lim>>1);
}
void ntt(int *x,int opt){
	for(int i=0;i<lim;i++)
		if(r[i]<i)swap(x[i],x[r[i]]);
	for(int p=2,k=1;p<=lim;p<<=1,k<<=1){
		gn=qpow(3,(P-1)/p);
		for(int i=0;i<lim;i+=p){
			for(int j=0,g=1;j<k;j++,g=1ll*g*gn%P){
				tp=1ll*x[i+j+k]*g%P;
				x[i+j+k]=(x[i+j]-tp+P)%P;
				x[i+j]=(x[i+j]+tp)%P;
			}
		}
	}
	if(opt==-1){
		reverse(x+1,x+lim),inv=qpow(lim,P-2);
		for(int i=0;i<lim;i++)
			x[i]=1ll*x[i]*inv%P;
	}
}
void Inv(int *a,int *b,int n){
	if(n==1){
		b[0]=qpow(a[0],P-2);
		return;
	}
	Inv(a,b,(n+1)>>1);
	lim=1;while(lim<(n<<1))lim<<=1;
	init_r(lim);
	for(int i=0;i<lim;i++)A[i]=i<n?a[i]:0;
	ntt(A,1),ntt(b,1);
	for(int i=0;i<lim;i++)
		b[i]=1ll*b[i]*((2ll-1ll*A[i]*b[i]%P+P)%P)%P;
	ntt(b,-1);
	for(int i=n;i<lim;i++)b[i]=0;
}
void Ln(int *a,int *b,int n){
	for(int i=0;i<(n<<2);i++)b[i]=0;
	Inv(a,b,n);
	lim=1;while(lim<(n<<1))lim<<=1;
	init_r(lim);
	for(int i=0;i<n-1;i++)
		a2[i]=1ll*a[i+1]*(i+1)%P;
	for(int i=n-1;i<lim;i++)a2[i]=0;
	ntt(a2,1),ntt(b,1);
	for(int i=0;i<lim;i++)
		b[i]=1ll*b[i]*a2[i]%P;
	ntt(b,-1);
	for(int i=n-1;i;i--)
		b[i]=1ll*b[i-1]*iv[i]%P;
	for(int i=n;i<lim;i++)b[i]=0;
	b[0]=0;
}
void Exp(int *a,int *b,int n){
	if(n==1){
		b[0]=1;
		return;
	}
	Exp(a,b,(n+1)>>1);
	Ln(b,lnb,n);
	lim=1;while(lim<(n<<1))lim<<=1;
	init_r(lim);
	for(int i=0;i<n;i++)
		lnb[i]=(a[i]-lnb[i]+P)%P;
	for(int i=n;i<lim;i++)lnb[i]=b[i]=0;
	lnb[0]++;
	ntt(lnb,1),ntt(b,1);
	for(int i=0;i<lim;i++)
		b[i]=1ll*b[i]*lnb[i]%P;
	ntt(b,-1);
	for(int i=n;i<lim;i++)b[i]=0;
}

其他

笛卡尔树

小根堆,编号满足 BST 性质。

点击查看代码
for(int i=1;i<=n;i++){
	while(tp&&a[st[tp]]>a[i])ls[i]=st[tp--];
	if(st[tp])rs[st[tp]]=i;
	st[++tp]=i;
}
posted @ 2024-02-29 21:12  SError  阅读(18)  评论(0编辑  收藏  举报