回文自动机:
要是不卡空间我多半就懒得写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;}
垃圾编辑器又要炸了,过会再开一篇。