前言
所有代码中未加的默认加上“#define ll long long”
Dinic的板子打错了好多遍,现在改过来了,非常抱歉
上一页:C++竞赛常用实用代码(4)
目录
线性筛求欧拉函数
int ph[MAXN];
bool nop[MAXN];
vector<int>pri;//素数集
inline void getphi(int n){//套用欧拉筛
nop[0]=nop[1]=1;
for(int i=1;i<=n;i++)ph[i]=i;
for(int a=2;a<=n;a++){
if(!nop[a])pri.push_back(a),ph[a]=a-1;
for(int i=0,u;i<pri.size()&&pri[i]*a<=n;i++){
u=pri[i]*a,nop[u]=1;
if(a%pri[i]==0)ph[u]=ph[a]*pri[i],i=MAXN;
else ph[u]=ph[a]*ph[pri[i]];
}
}
}
线性筛求莫比乌斯函数
int mu[MAXN];
bool nop[MAXN];
vector<int>pri;//素数集
inline void getmu(int n){//套用欧拉筛
mu[1]=1,nop[0]=nop[1]=1;
for(int a=2;a<=n;a++){
if(!nop[a])pri.push_back(a),mu[a]=-1;
for(int i=0,u;i<pri.size()&&pri[i]*a<=n;i++){
u=pri[i]*a,nop[u]=1;
if(a%pri[i]==0)mu[u]=0,i=MAXN;
else mu[u]=-mu[a];
}
}
}
快速傅里叶变换(FFT)
#define cp complex<double> //记得加上<complex>头文件
const double pi=acos(-1);
int rev[MAXN];
inline int FFT_IFFT(cp*a,int N,int inv){
int bit=0,n=N;
while((1<<bit)<n)bit++;n=(1<<bit);//把n扩成2的次幂
for(int i=0;i<n;i++){
rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
if(i<rev[i])swap(a[i],a[rev[i]]);
}cp tmp,omega,y;
for(int mid=1;mid<n;mid<<=1){
tmp=cp(cos(pi/mid),inv*sin(pi/mid)),omega=cp(1,0);
for(int i=0;i<n;i+=(mid<<1),omega=cp(1,0))
for(int j=0;j<mid;j++,omega*=tmp)
y=omega*a[i+j+mid],a[i+j]+=y,a[i+j+mid]=a[i+j]-y-y;
}
if(inv<0)for(int i=0;i<n;i++)a[i].real()/=n;//逆变换要除以n
return n;//返回数组长度
}
inline int FFT(cp*a,int n){return FFT_IFFT(a,n,1);}
inline int IFFT(cp*a,int n){return FFT_IFFT(a,n,-1);}
快速数论变换(NTT)
inline ll ksm(ll a,ll b,ll mo){//快速幂
ll res=1;
for(;b;b>>=1,a=a*a%mo)if(b&1)res=res*a%mo;
return res;
}
#define mod 998244353ll //模数一般为998244353
#define g 3ll //原根
int rev[MAXN<<1];
inline ll ksm(ll a,ll b,ll mo){//快速幂
ll res=1;
for(;b;b>>=1,a=a*a%mo)if(b&1)res=res*a%mo;
return res;
}
inline int NTT_INTT(int*a,int N,int inv){
int bit=0,n=N;
while((1<<bit)<n)bit++;n=(1<<bit);//把n扩成2的次幂
for(int i=0;i<n;i++){
rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
if(i<rev[i])swap(a[i],a[rev[i]]);
}
for(int mid=1;mid<n;mid<<=1){
ll tmp=ksm(g,(mod-1)/(mid<<1),mod),om=1,y;
if(inv<0)tmp=ksm(tmp,mod-2,mod);
for(int i=0;i<n;i+=(mid<<1),om=1)
for(int j=0;j<mid;j++,om=(om*tmp)%mod)
y=om*a[i+j+mid]%mod,a[i+j]=(y+a[i+j])%mod,a[i+j+mid]=((mod-y<<1)+a[i+j])%mod;
}
if(inv<0)for(int i=0,in=ksm(n,mod-2,mod);i<n;i++)a[i]=1ll*in*a[i]%mod;//逆变换乘n的逆元
return n;//返回数组大小
}
inline int NTT(int*a,int n){return NTT_INTT(a,n,1);}
inline int INTT(int*a,int n){return NTT_INTT(a,n,-1);}
快速沃尔什变换FWT(改进)
//所有函数中传入inv=1表示正变换,-1表示逆变换
inline void FWTOR(int*a,int n,int inv){ //按位或
for(int k=2;k<=n;k<<=1)//k的枚举从大到小和从小到大,结果是完全一样的
for(int i=0;i<n;i+=k)
for(int j=i;j<i+(k>>1);j++)
a[j+(k>>1)]=(a[j+(k>>1)]+a[j]*inv+MOD)%MOD;
}
inline void FWTAND(int*a,int n,int inv){ //按位与
for(int k=2;k<=n;k<<=1)
for(int i=0;i<n;i+=k)
for(int j=i;j<i+(k>>1);j++)
a[j]=(a[j]+a[j+(k>>1)]*inv+MOD)%MOD;
}
//此处应有个快速幂
inline void FWTXOR(int*a,int n,int inv){ //异或
ll in2=inv>0?1:ksm(2,MOD-2,MOD),a0,a1;
for(int k=2;k<=n;k<<=1)
for(int i=0;i<n;i+=k)
for(int j=i;j<i+(k>>1);j++)
a0=a[j],a1=a[j+(k>>1)],a[j]=(a0+a1)%MOD*in2%MOD,a[j+(k>>1)]=(a0-a1+MOD)%MOD*in2%MOD;
}
快速莫比乌斯变换(FMT)
主要用来代替FWT的按位或、与部分,用法相同
inline void FMTOR(int*a,int n,int inv){//按位或
for(int k=1;k<n;k<<=1)
for(int i=0;i<n;i++)
if(~i&k)a[i|k]=(a[i|k]+a[i]*inv+MOD)%MOD;
}
inline void FMTAND(int*a,int n,int inv){//按位与
for(int k=1;k<n;k<<=1)
for(int i=n-1;i>=0;i--)
if(i&k)a[i^k]=(a[i^k]+a[i]*inv+MOD)%MOD;
}
更多有关快速沃尔什变换和莫比乌斯变换
匈牙利算法模板
int mat[MAXN];
vector<int>G[MAXN];
bool vis[MAXN];
inline bool findh(int x){
for(int i=0;i<G[x].size();i++)
if(!vis[G[x][i]]){
int v=G[x][i];vis[v]=1;
if(mat[v]<0||findh(mat[v])){
mat[v]=x;return 1;
}
}
return 0;
}
inline int hungary(){
memset(mat,-1,sizeof(mat));
int res=0;
for(int i=0;i<n;i++){
memset(vis,0,sizeof(vis));
if(findh(i))res++;
}
return res;
}
最大流Dinic算法模板
#define INF 0x3f3f3f3f
int d[MAXN],cur[MAXN];
ll f[MAXN];
struct edge{
int v,id,fd;edge(){}
edge(int V,int I,int F){v=V,id=I,fd=F;}
};
vector<edge>G[MAXN];
queue<int>q;
inline bool bfs(int S,int T){
while(!q.empty())q.pop();
memset(d,-1,sizeof(d));
d[S]=0,q.push(S);
while(!q.empty()){
int u=q.front();q.pop();
for(int i=0;i<G[u].size();i++)
if(f[G[u][i].id]>0&&d[G[u][i].v]<0)
d[G[u][i].v]=d[u]+1,q.push(G[u][i].v);
}
return d[T]>=0;
}
inline ll dfs(int x,ll lim,int T){
if(x==T)return lim;
ll res=lim;
for(int i=cur[x];i<G[x].size()&&res>0;i++){
cur[x]=i;
int v=G[x][i].v,a=G[x][i].id,b=G[x][i].fd;
if(f[a]>0&&d[v]==d[x]+1){
int ad=dfs(v,min(res,f[a]),T);
f[a]-=ad,f[b]+=ad,res-=ad;
}
}
return lim-res;
}
inline ll dinic(int S,int T){
ll res=0;
while(bfs(S,T)){
memset(cur,0,sizeof(cur));
while(ll ad=dfs(S,INF,T))res+=ad;
}
return res;
}
二分图最大权完美匹配KM算法模板
递归版():
int n,mat[505];
ll w[505][505],exg[505],exb[505],lak[505];
bool vg[505],vb[505];
inline bool dfs(int x){
vg[x]=1;
for(int v=1;v<=n;v++)
if(!vb[v]){
ll gap=exg[x]+exg[v]-w[x][v];
if(gap==0){
vb[v]=1;
if(mat[v]<0||dfs(mat[v])){
mat[v]=x;return 1;
}
}
else lak[v]=min(lak[v],gap);
}
return 0;
}
inline ll KM(){
memset(mat,-1,sizeof(mat));
mst0(exb);
for(int i=1;i<=n;i++){
exg[i]=w[i][1];
for(int j=2;j<=n;j++)
exg[i]=max(exg[i],w[i][j]);
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++)lak[j]=INF;
while(1){
mst0(vg);mst0(vb);
if(dfs(i))break;
ll ad=INF;
for(int j=1;j<=n;j++)
if(!vb[j])ad=min(ad,lak[j]);
for(int j=1;j<=n;j++){
if(vg[j])exg[j]-=ad;
if(vb[j])exb[j]+=ad;
else lak[j]-=ad;
}
}
}
ll res=0;
for(int i=1;i<=n;i++)res+=w[mat[i]][i]-ADD;
return res;
}
BFS版():
int n,mat[505],pre[505];
ll w[505][505],exg[505],exb[505],lak[505];
bool vb[505];
inline void bfs(int pg){
int x,y=0,by=0;ll ad;
mst0(pre);
memset(lak,0x7f,sizeof(lak));
mat[y]=pg;
do{
x=mat[y],ad=INF,vb[y]=1;
for(int i=1;i<=n;i++)
if(!vb[i]){
ll gap=exg[x]+exb[i]-w[x][i];
if(lak[i]>gap)lak[i]=gap,pre[i]=y;
if(lak[i]<ad)ad=lak[i],by=i;
}
for(int i=0;i<=n;i++){
if(vb[i])exg[mat[i]]-=ad,exb[i]+=ad;
else lak[i]-=ad;
}
y=by;
}while(mat[y]!=0);
while(y)mat[y]=mat[pre[y]],y=pre[y];
}
inline ll KM(){
mst0(mat);mst0(exb);mst0(exg);
for(int i=1;i<=n;i++)mst0(vb),bfs(i);
ll res=0;
for(int i=1;i<=n;i++)res+=w[mat[i]][i]-ADD;
return res;
}
SPFA求费用流模板
重拾SPFA
ll w[MAXM],c[MAXM],f[MAXN],d[MAXN],ansf,ansc;
int pre[MAXN],las[MAXN];
struct edge{
int v,id;edge(){}
edge(int V,int I){v=V,id=I;}
};
vector<edge>G[MAXN];
bool vis[MAXN];
queue<int>q;
inline bool SPFA(int S,int T){
memset(d,0x7f,sizeof(d));
memset(vis,0,sizeof(vis));
memset(f,0x7f,sizeof(f));
q.push(S),d[S]=0,vis[S]=1,pre[T]=-1;
while(!q.empty()){
int u=q.front();q.pop(),vis[u]=0;
for(int i=0;i<G[u].size();i++){
int v=G[u][i].v,a=G[u][i].id;
if(w[a]>0&&d[v]>d[u]+c[a]){
d[v]=d[u]+c[a],f[v]=min(f[u],w[a]);
pre[v]=u,las[v]=a;
if(!vis[v])vis[v]=1,q.push(v);
}
}
}
return pre[T]>=0;
}
inline void ildfs(int S,int T){ //Illusory-DFS,虚假深搜
ansf+=f[T],ansc+=f[T]*d[T];
for(int x=T;x!=S;x=pre[x])
w[las[x]]-=f[T],w[las[x]^1]+=f[T];
}
Always to be continued(持续更新中)...