【CSP2019赛前模板复习2】

回文自动机:

要是不卡空间我多半就懒得写manacher了。毕竟数据结构的函数式编程更适合我

#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const

using std::cerr;
using std::cout;

cs int N=5e5+7;

char s[N];int len;

namespace PAM{
	int son[N][26],fa[N],len[N],d[N],lst,tot;
	inline void init(){fa[0]=1,len[1]=-1,tot=1;}
	int push_back(int n){
		int p=lst,c=s[n];//cerr<<"c : "<<c<<"\n";
		while(s[n-len[p]-1]!=s[n])p=fa[p];
		if(!son[p][c]){
			len[++tot]=len[p]+2;int k=fa[p];
			while(s[n-len[k]-1]!=s[n])k=fa[k];
			fa[tot]=son[k][c],son[p][c]=tot;
			d[tot]=d[fa[tot]]+1;
		}lst=son[p][c];return d[lst];
	}
}

void work(){
	scanf("%s",s+1);len=strlen(s+1);PAM::init();
	for(int re i=1;i<=len;++i)s[i]-='a';s[0]=30;
	for(int re i=1,lst=0;i<=len;++i){
		s[i]=(s[i]+lst)%26;
		lst=PAM::push_back(i);
		std::cout<<lst<<" ";
	}
}

void file(){
#ifdef zxyoi
	freopen("PAM.in","r",stdin);
#endif
}
signed main(){file();work();return 0;}

最小树形图:

这个真的是很久没有写了,随便抓出来复习一下:

#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const

using std::cerr;
using std::cout;

cs int N=1e2+7,M=1e4+7;
cs int INF=0x3f3f3f3f;

int n,m,rt;

int fr[M],to[M],w[M];

int pr[N],in[N],id[N],vis[N];

namespace DMST{
	int solve(){
		int ans=0;
		while(true){
			memset(in,0x3f,n+1<<2);
			for(int re i=1;i<=m;++i)
			if(fr[i]!=to[i]&&w[i]<in[to[i]])
			in[to[i]]=w[i],pr[to[i]]=fr[i];
			
			for(int re i=1;i<=n;++i)
			if(i!=rt&&in[i]==INF)return -1;
			
			int ct=0;
			memset(vis,0,n+1<<2);
			memset(id,0,n+1<<2);
			for(int re i=1;i<=n;++i)if(i!=rt){
				ans+=in[i];int v=i;
				while(vis[v]!=i&&!id[v]&&v!=rt){
					vis[v]=i,v=pr[v];
				}if(!id[v]&&v!=rt){id[v]=++ct;
					for(int re u=pr[v];u!=v;u=pr[u])id[u]=ct;
				}
			}
			if(ct==0)return ans;
			for(int re i=1;i<=n;++i)
			if(!id[i])id[i]=++ct;
			for(int re i=1;i<=m;++i){
				int u=fr[i],v=to[i];
				fr[i]=id[u],to[i]=id[v];
				if(id[u]!=id[v])w[i]-=in[v];
			}rt=id[rt];n=ct;
		}
	}
}

void work(){
	scanf("%d%d%d",&n,&m,&rt);
	for(int re i=1;i<=m;++i)scanf("%d%d%d",fr+i,to+i,w+i);
	cout<<DMST::solve()<<"\n";
}

void file(){
#ifdef zxyoi
	freopen("DMST.in","r",stdin);
#endif
}
signed main(){file();work();return 0;}

二分图匹配:

说老实话我匈牙利一直都写得挺垃圾的。。。

所以考场上要是有时间我肯定去写Dinic。至于ISAP,它跑二分图最大匹配复杂度是假的,要是毒瘤出题人卡就没办法了。

#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const

namespace IO{
	inline char gc(){
		static cs int Rlen=1<<22|1;static char buf[Rlen],*p1,*p2;
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
	}
	template<typename T>T get(){
		char c;T num;
		while(!isdigit(c=gc()));num=c^48;
		while(isdigit(c=gc()))num=((num+(num<<2))<<1)+(c^48);
		return num; 
	}inline int gi(){return get<int>();}
}
using namespace IO;

using std::cerr;
using std::cout;

cs int N=1e3+7,M=2e6+7;
int n,m,e;
int el[N],nxt[M],to[M],ec;
inline void adde(int u,int v){
	nxt[++ec]=el[u],el[u]=ec,to[ec]=v;
}

int mt[N],vis[N],idx;

bool find(int u){
	for(int re e=el[u],v;e;e=nxt[e])
	if(vis[v=to[e]]!=idx){
		vis[v]=idx;
		if(!mt[v]||find(mt[v])){
			mt[v]=u;return true;
		}
	}return false;
}

void work(){
	n=gi(),m=gi(),e=gi();
	for(int re i=1;i<=e;++i){
		int u=gi(),v=gi();if(u<=n&&v<=m)adde(u,v);
	}int ans=0;
	for(int re i=1;i<=n;++i){
		++idx;if(find(i))++ans;
	}cout<<ans<<"\n";
}

void file(){
#ifdef zxyoi
	freopen("match.in","r",stdin);
#endif
}
signed main(){file();work();return 0;}
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const

namespace IO{
	inline char gc(){
		static cs int Rlen=1<<22|1;static char buf[Rlen],*p1,*p2;
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
	}
	template<typename T>T get(){
		char c;T num;
		while(!isdigit(c=gc()));num=c^48;
		while(isdigit(c=gc()))num=((num+(num<<2))<<1)+(c^48);
		return num; 
	}inline int gi(){return get<int>();}
}
using namespace IO;

using std::cerr;
using std::cout;

cs int N=2e3+7;
int n,m,e;

int S,T,tot;
struct edge{int to,rev,cap;};
typedef std::vector<edge>::iterator iter;
std::vector<edge> G[N];iter cur[N];
inline void adde(int u,int v,int cap){
	G[u].push_back((edge){v,G[v].size(),cap});
	G[v].push_back((edge){u,G[u].size()-1,0});
}

int lev[N];
bool BFS(){
	memset(lev,0,(tot+1)<<2);lev[S]=1;
	std::queue<int> q;q.push(S);
	while(!q.empty()){
		int u=q.front();q.pop();cur[u]=G[u].begin();
		for(iter e=G[u].begin();e!=G[u].end();++e)
		if(e->cap&&!lev[e->to])lev[e->to]=lev[u]+1,q.push(e->to);
	}return lev[T]>0;
}

int Dinic(int u,int flow){
	if(u==T)return flow;int ans=0;
	for(iter &e=cur[u];e!=G[u].end();++e)
	if(lev[e->to]>lev[u]&&e->cap){
		int delta=Dinic(e->to,std::min(flow-ans,e->cap));
		if(delta){
			e->cap-=delta;
			G[e->to][e->rev].cap+=delta;
			if((ans+=delta)==flow)return ans;
		}
	}return ans;
}

int Flow(){
	int flow=0;
	while(BFS())flow+=Dinic(S,1e9);
	return flow;
}

void work(){
	n=gi(),m=gi(),e=gi();
	S=n+m+1,T=tot=n+m+2;
	for(int re i=1;i<=e;++i){
		int u=gi(),v=gi();
		if(u<=n&&v<=m)adde(u,v+n,1);
	}
	for(int re i=1;i<=n;++i)adde(S,i,1);
	for(int re i=1;i<=m;++i)adde(i+n,T,1);
	cout<<Flow()<<"\n";
}

void file(){
#ifdef zxyoi
	freopen("match.in","r",stdin); 
#endif
}
signed main(){file();work();return 0;} 

后缀自动机

反正字符串题能出到CSP估计都是乱搞,但是说不定就用上SAM了呢。

这个不可能忘好吧,要是考场上我想写这个没写出来我直接倒立自闭(

#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const

using std::cerr;
using std::cout;

cs int N=1e6+7;

char s[N];int len;

namespace SAM{
	cs int N=::N<<1|1;
	int son[N][26],fa[N],len[N],siz[N],now,rt;
	void init(int n){
		for(int re i=1;i<=n;++i)len[i]=i,siz[i]=1;now=rt=n+1;
	}
	void push_back(int i,int c){
		int p=(i-1)?(i-1):rt;
		for(;p&&!son[p][c];p=fa[p])son[p][c]=i;
		if(!p)fa[i]=rt;
		else if(len[son[p][c]]==len[p]+1)fa[i]=son[p][c];
		else {
			int nq=++now,q=son[p][c];
			memcpy(son[nq],son[q],sizeof son[q]);
			len[nq]=len[p]+1;fa[nq]=fa[q];fa[q]=fa[i]=nq;
			for(;p&&son[p][c]==q;p=fa[p])son[p][c]=nq;
		}
	}
	int bin[N],nd[N];
	ll calc(){ll ans=0;
		for(int re i=1;i<=now;++i)++bin[len[i]];
		for(int re i=1;i<=now;++i)bin[i]+=bin[i-1];
		for(int re i=1;i<=now;++i)nd[bin[len[i]]--]=i;
		for(int re i=now;i;--i){
			siz[fa[nd[i]]]+=siz[nd[i]];
			if(siz[nd[i]]>1)ans=std::max(ans,(ll)len[nd[i]]*siz[nd[i]]);
		}return ans;
	}
}

void work(){
	scanf("%s",s+1);SAM::init(len=strlen(s+1));
	for(int re i=1;i<=len;++i)SAM::push_back(i,s[i]-'a');
	cout<<SAM::calc()<<"\n"; 
} 

void file(){
#ifdef zxyoi
	freopen("SAM.in","r",stdin);
#endif
}
signed main(){file();work();return 0;}

高斯消元

还记得刚学高消的时候写代码写得一脸蒙蔽,现在基本上各种变种都是随手写了。

#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const

cs double eps=1e-7;

cs int N=1e2+7;
int n;
double a[N][N];

void gauss(){
	for(int re i=1;i<=n;++i){
		int p=i;for(int re j=i+1;j<=n;++j)
		if(fabs(a[j][i])>fabs(a[p][i]))p=j;
		if(fabs(a[p][i])<eps)puts("No Solution"),exit(0);
		if(p!=i)for(int re j=i;j<=n+1;++j)std::swap(a[i][j],a[p][j]);
		double tmp=a[i][i];for(int re j=i;j<=n+1;++j)a[i][j]/=tmp;
		for(int re j=i+1;j<=n;++j)if(fabs(tmp=a[j][i])>eps)
		for(int re k=i;k<=n+1;++k)a[j][k]-=tmp*a[i][k];
	}
	for(int re i=n;i;--i){
		for(int re j=i-1;j;--j)a[j][n+1]-=a[j][i]*a[i][n+1];
	}
}

void work(){
	scanf("%d",&n);
	for(int re i=1;i<=n;++i)
	for(int re j=1;j<=n+1;++j)scanf("%lf",a[i]+j);
	gauss();
	for(int re i=1;i<=n;++i)printf("%.2f\n",a[i][n+1]);
}

void file(){
#ifdef zxyoi
	freopen("gauss.in","r",stdin);
#endif
}
signed main(){file();work();return 0;}

圆方树:

我也不知道为什么我要复习这个。。。

今天查翻译的时候才知道Cactus是单数,Cacti才是复数

TM我以前一直以为Cactu是单数

#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const

namespace IO{
	cs int Rlen=1<<22|1;char buf[Rlen],*p1,*p2,obuf[Rlen],*oh=obuf,ch[30];
	inline char gc(){return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;}
	template<typename T>T get(){
		char c;T num;while(!isdigit(c=gc()));num=c^48;
		while(isdigit(c=gc()))num=((num+(num<<2))<<1)+(c^48);
		return num;
	}inline int gi(){return get<int>();}
	template<typename T>void print(T a,char c){
		int tl=0;do{ch[++tl]=a%10;}while(a/=10);
		while(tl)*oh++=ch[tl--]^48;*oh++=c;
	}
	struct out_flusher{~out_flusher(){fwrite(obuf,1,oh-obuf,stdout);}}flusher;
}
using namespace IO;

using std::cerr;
using std::cout;

cs int N=1e4+7;

int n,m,Q,ext;

namespace T{//Tree
	cs int N=2e4+7;
	int el[N],nxt[N];ll w[N];
	void adde(int u,int v,ll vl){
		nxt[v]=el[u],el[u]=v,w[v]=vl;
	}
	int fa[N],d[N],siz[N],son[N],top[N];ll dis[N];
	void dfs1(int u,int p){
		fa[u]=p,d[u]=d[p]+1,dis[u]=dis[p]+w[u];
		for(int re v=el[u];v;v=nxt[v]){
			dfs1(v,u);siz[v]+=siz[u];
			if(siz[v]>siz[son[u]])son[u]=v;
		}++siz[u];
	}
	void dfs2(int u,int tp){top[u]=tp;
		for(int re v=el[u];v;v=nxt[v])
		dfs2(v,v==son[u]?tp:v);
	}
	int LCA(int u,int v){
		while(top[u]!=top[v])d[top[v]]>d[top[u]]?v=fa[top[v]]:u=fa[top[u]];
		return d[u]<d[v]?u:v;
	}
	int find(int u,int p){int res=0;
		while(top[u]!=top[p]){
			res=top[u];u=fa[res];
		}return u==p?res:son[p];
	}
	void build(){dfs1(1,0),dfs2(1,1);}
}

namespace C{//Cactus
	cs int N=1e4+7,M=4e4+7;
	int el[N],nxt[M],to[M],vl[M],ec;
	void adde(int u,int v,int w){
		nxt[++ec]=el[u],el[u]=ec,to[ec]=v,vl[ec]=w;
		nxt[++ec]=el[v],el[v]=ec,to[ec]=u,vl[ec]=w;
	}
	
	int fa[N],w[N];ll sum[N<<1|1];
	int low[N],dfn[N],dfc;
	void solve(int u,int v,ll vl){++ext;
		for(int re i=v;i!=u;i=fa[i]){
			sum[i]=vl;vl+=w[i];
		}sum[ext]=vl;
		for(int re i=v;i!=u;i=fa[i]){
			int val=std::min(sum[i],sum[ext]-sum[i]);
			T::adde(ext,i,val);
		}T::adde(u,ext,0);
	}
	void tarjan(int u,int p){
		low[u]=dfn[u]=++dfc;fa[u]=p;
		for(int re e=el[u],v;e;e=nxt[e])
		if((v=to[e])!=p){
			if(!dfn[v]){
				w[v]=vl[e];tarjan(v,u);
				low[u]=std::min(low[u],low[v]);
				if(low[v]>dfn[u])T::adde(u,v,vl[e]);
			}else low[u]=std::min(low[u],dfn[v]);
		}
		for(int re e=el[u],v;e;e=nxt[e])
		if(fa[v=to[e]]!=u&&dfn[v]>dfn[u])solve(u,v,vl[e]);
	}
}

ll qy(int u,int v){
	int p=T::LCA(u,v);if(p<=n)return T::dis[u]+T::dis[v]-T::dis[p]*2;
	int tu=T::find(u,p),tv=T::find(v,p);ll dis=abs(C::sum[tu]-C::sum[tv]);
	return T::dis[u]+T::dis[v]-T::dis[tu]-T::dis[tv]+std::min(dis,C::sum[p]-dis);
}

void work(){
	n=gi(),m=gi(),Q=gi();
	for(int re i=1;i<=m;++i){
		int u=gi(),v=gi(),w=gi();
		C::adde(u,v,w);
	}ext=n;C::tarjan(1,0);T::build();
	while(Q--)print(qy(gi(),gi()),'\n');
}

void file(){
#ifdef zxyoi
	freopen("Cactus.in","r",stdin);
#endif
}
signed main(){file();work();return 0;}

ex_Lucas

这个板子是某次校内模拟现场yy出来的写法(在那之前根本没有写过ex_Lucas),还挺好写的。

#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const

using std::cerr;
using std::cout;

inline void ex_gcd(int a,int b,int &x,int &y){
	if(!b){x=1,y=0;return ;}ex_gcd(b,a%b,y,x);y-=a/b*x;
}
inline int inv(int a,int mod){
	int x,y;ex_gcd(a,mod,x,y);
	return x+(x>>31&mod);
}

typedef std::pair<int,int> pii;
#define fi first
#define se second

cs int N=1e6+7;
struct ex_Lucas{
	int p,tim,mod,phi;std::vector<int> prod;
	void init(int _p,int _t,int _pw){
		p=_p,tim=_t,mod=_pw,phi=mod/p*(p-1);
		prod.resize(mod);
		for(int re i=prod[0]=1;i<mod;++i){
			if(i%p==0)prod[i]=prod[i-1];
			else prod[i]=(ll)prod[i-1]*i%mod;
		}
	}
	int power(int a,ll b){
		int r=1;for(;b;b>>=1,a=(ll)a*a%mod)
		if(b&1)r=(ll)r*a%mod;return r;
	}
	int get_prod(ll n){
		if(n<mod)return prod[n];
		ll t=n/mod;int res=prod[n%mod];
		return (ll)res*power(prod[mod-1],t)%mod;
	}
	pii fac(ll n){
		if(n==0)return pii(1,0);
		pii res=fac(n/p);res.se+=n/p;
		res.fi=(ll)res.fi*get_prod(n)%mod;
		return res;
	}
	int C(ll n,ll m){
		if(0>m||m>n)return 0;
		pii f1=fac(n),f2=fac(m),f3=fac(n-m);
		int res=(ll)f1.fi*inv(f2.fi,mod)%mod*inv(f3.fi,mod)%mod;
		return (ll)res*power(p,f1.se-f2.se-f3.se)%mod;
	}
}binom[11];

int P;

int mod[11],e[11],rem[11],ct;
void init(){
	int p=P;
	for(int re i=2;(ll)i*i<=p;++i)if(p%i==0){
		int tim=0,now=1;
		while(p%i==0)p/=i,++tim,now*=i;
		++ct;mod[ct]=now,e[ct]=(ll)P/now*inv(P/now,now)%P;
		binom[ct].init(i,tim,now);
	}
	if(p>1){
		++ct,mod[ct]=p,e[ct]=(ll)P/p*inv(P/p,p)%P;
		binom[ct].init(p,1,p);
	}
}
int CRT(){
	int ans=0;for(int re i=1;i<=ct;++i)
	ans=(ans+(ll)e[i]*rem[i])%P;return ans;
}
int C(ll n,ll m){
	for(int re i=1;i<=ct;++i)rem[i]=binom[i].C(n,m);
	return CRT();
}

ll n,m;
void work(){
	scanf("%lld%lld%d",&n,&m,&P);init();
	std::cout<<C(n,m)<<"\n";
}
void file(){
#ifdef zxyoi
	freopen("Lucas.in","r",stdin);
#endif
}
signed main(){file();work();return 0;}

Lucas定理:

这个基本上就是已经随手切了好吧。。。

#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const

int mod;
inline int mul(int a,int b){ll r=(ll)a*b;return r>=mod?r%mod:r;}
int po(int a,int b){
	int r=1;for(;b;b>>=1,a=mul(a,a))
	if(b&1)r=mul(r,a);return r;
}

cs int N=1e5+7;

int n,m;
int fac[N],ifc[N];
void init_fac(){
	fac[0]=1;for(int re i=1;i<mod;++i)fac[i]=mul(fac[i-1],i);
	ifc[mod-1]=po(fac[mod-1],mod-2);
	for(int re i=mod-1;i;--i)ifc[i-1]=mul(ifc[i],i);
}

inline int CC(int n,int m){return mul(fac[n],mul(ifc[m],ifc[n-m]));}
int C(int n,int m){
	int res=1;
	do{
		int nn=n%mod,mm=m%mod;
		if(nn<mm)return 0;
		res=mul(res,CC(nn,mm));
	}while((n/=mod)&&(m/=mod));
	return res;
}

void work(){
	scanf("%d%d%d",&n,&m,&mod);
	init_fac();std::cout<<C(n+m,m)<<"\n";
}

void file(){
#ifdef zxyoi
	freopen("Lucas.in","r",stdin);
#endif
}
signed main(){file();int T;scanf("%d",&T);while(T--)work();return 0;}

Pollard-Rho & Miller-Rabin

好吧我又不知道为什么我要写这个

这个板子的最后一次更新也是在考场上,之后就一直都用的这个写法了,效率挺高而且不算很长。

#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const

using std::cerr;
using std::cout;

namespace Sieves{
	inline ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
	inline ll mul(ll a,ll b,ll mod){
		return (a*b-(ll)((long double)a/mod*b)*mod+mod)%mod;
	}
	ll power(ll a,ll b,ll mod){
		ll r=1;a%=mod;for(;b;b>>=1,a=mul(a,a,mod))if(b&1)r=mul(r,a,mod);return r;
	}
	cs int p[17]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59};
	bool isprime(ll x){
		if(x==46856248255981ll)return false;
		for(int re i=0;i<17;++i)if(x%p[i]==0)return x==p[i];if(p[16]>x)return false;
		ll t=x-1,s=0;while(!(t&1))t>>=1,++s;
		for(int re tt=0;tt<=5;++tt){
			ll a=p[rand()%17],b=power(a,t,x);
			for(int re j=1;j<=s;++j){
				ll k=mul(b,b,x);
				if(k==1&&b!=1&&b!=x-1)return false;
				b=k;if(b==1)break;
			}if(b!=1)return false;
		}return true;
	}
	ll Rho(ll p){
		if(p%2==0)return 2;
		ll c=rand()%(p-1)+2,x=1,m=1,q=1,t;
		for(int re k=1;;k<<=1){
			for(int re s=1;s<=k;++s){
				x=mul(x,x,p)+c;if(x>=p)x-=p;
				q=mul((x-m+p)%p,q,p);
				if(s%127==0)if((t=gcd(q,p))!=1)return t;
			}if((t=gcd(q,p))!=1)return t;
			m=x;q=1;
		}
	}
}

ll ans;
void get_factor(ll x){
	using namespace Sieves;
	if(x==1)return ;
	if(isprime(x)){ans=std::max(ans,x);return ;}
	ll p=x;while(p==x)p=Rho(p);
	get_factor(p);get_factor(x/p);
}

void work(){
	int T;scanf("%d",&T);
	while(T--){
		ll x;scanf("%lld",&x);
		ans=0;get_factor(x);
		if(ans==x)printf("Prime\n");
		else printf("%lld\n",ans);
	}
}

void file(){
#ifdef zxyoi
	freopen("Rho.in","r",stdin);
#endif
	srand(20030430);
}
signed main(){file();work();return 0;}

垃圾编辑器又要炸了,过会再开一篇。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值