0% found this document useful (0 votes)
8 views

XCPC板子

The document discusses various mathematical and algorithmic concepts related to polynomial technology, graph theory, string processing, and data structures. It includes detailed code implementations for polynomial operations such as multiplication, inversion, and evaluation, as well as techniques for fast interpolation and number-theoretic transforms. Key topics covered include NTT (Number Theoretic Transform), matrix trees, and algorithms for solving problems in combinatorial optimization.

Uploaded by

lpfoier
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
8 views

XCPC板子

The document discusses various mathematical and algorithmic concepts related to polynomial technology, graph theory, string processing, and data structures. It includes detailed code implementations for polynomial operations such as multiplication, inversion, and evaluation, as well as techniques for fast interpolation and number-theoretic transforms. Key topics covered include NTT (Number Theoretic Transform), matrix trees, and algorithms for solving problems in combinatorial optimization.

Uploaded by

lpfoier
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 104

【1】多项式科技

【2】数学相关
原根
Pollard-Rho
矩阵树、LGV、BEST
筛法
子集卷积
exBSGS
二次剩余
Lucas 定理与 ExLucas
exCRT
FWT
【3】图论相关
2-SAT
Prufer 序列
支配树
欧拉路径
Dinic 与 费用流
割点
最小树形图
最小斯坦纳树
边双
二分图最大匹配
二分图最大权完美匹配
【4】字符串相关
SA
AC自动机
最小表示法
PAM
SAM
【5】数据结构相关
平衡树与 LCT
点分树
左偏树
【1】多项式科技
多项式板子(ntt,求逆,exp,ln,快速幂)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double db;
const ll inf=1e18,N=2501001,MAX=2001,mod=998244353,inv3=
(mod+1)/3;
const db PI=acosl(-1);
typedef vector<ll> poly;
inline void read(ll &ret)
{
ret=0;char c=getchar();bool pd=false;
while(!isdigit(c)){pd|=c=='-';c=getchar();}
while(isdigit(c)){ret=(ret<<1)+(ret<<3)+
(c&15);c=getchar();}
ret=pd?-ret:ret;
return;
}
ll n;
inline ll qpow(ll a,long long b)
{
ll ret=1;
while(b)
{
if(b&1)
ret=1ll*ret*a%mod;
b>>=1;
a=1ll*a*a%mod;
}
return ret;
}
ll rev[N];
inline void ntt(poly &a,const ll n,const ll inv)
{
for(int i=0;i<n;i++)
{
if(i<rev[i])
swap(a[i],a[rev[i]]);
}
ll x,y,w,Wn;
ll c=inv==1?0:1;
for(int mid=1;mid<n;mid<<=1)
{
Wn=qpow(c?inv3:3,(mod-1)/(mid<<1));
for(int i=0;i<n;i+=mid<<1)
{
w=1;
for(int j=0;j<mid;j++,w=1ll*w*Wn%mod)
{
x=a[i+j],y=1ll*w*a[i+j+mid]%mod;
a[i+j]=x+y,a[i+j+mid]=x-y;
a[i+j]-=a[i+j]>=mod?mod:0;
a[i+j+mid]+=a[i+j+mid]<0?mod:0;
}
}
}
return;
}
inline poly operator *(poly a,poly b)
{
ll n=a.size(),m=b.size();
ll num=1,bit=0;
while(num<(n+m))
num<<=1,bit++;
a.resize(num);
b.resize(num);
for(int i=0;i<num;i++)
rev[i]=(rev[i>>1]>>1)|((i&1)<<bit-1);
ntt(a,num,1);
ntt(b,num,1);
poly c;
c.resize(num);
for(int i=0;i<num;i++)
c[i]=1ll*a[i]*b[i]%mod;
ntt(c,num,-1);
c.resize(n+m-1);
ll inv=qpow(num,mod-2);
for(int i=0;i<n+m-1;i++)
c[i]=1ll*c[i]*inv%mod;
return c;
}
inline poly inv(const ll n,poly a)
{
if(n==1)
return {qpow(a[0],mod-2)};
poly b=inv(n-(n>>1),a);
ll num=1,bit=0;
while(num<=(n<<1))
num<<=1,bit++;
a.resize(n);
a.resize(num);
b.resize(num);
for(int i=0;i<num;i++)
rev[i]=(rev[i>>1]>>1)|((i&1)<<bit-1);
ntt(a,num,1);
ntt(b,num,1);
for(int i=0;i<num;i++)
{
b[i]=1ll*b[i]*(2ll-1ll*a[i]*b[i]%mod)%mod;
b[i]+=b[i]<0?mod:0;
}
ntt(b,num,-1);
ll inv=qpow(num,mod-2);
for(int i=0;i<num;i++)
b[i]=1ll*inv*b[i]%mod;
b.resize(n);
return b;
}
inline poly derivate(const ll n,const poly &a)
{
poly b;
b.resize(n-1);
for(int i=0;i<n-1;i++)
b[i]=1ll*a[i+1]*(i+1)%mod;
return b;
}
inline poly integrate(const ll n,const poly &a)
{
poly b;
b.resize(n);
b[0]=0;
for(int i=n-1;i;i--)
b[i]=1ll*a[i-1]*qpow(i,mod-2)%mod;
return b;
}
inline poly getln(const ll n,const poly &a)
{
return integrate(n,derivate(n,a)*inv(n,a));
}
inline poly getexp(const ll n,const poly &a)
{
if(n==1)
return {1};
poly b=getexp(n-(n>>1),a);
b.resize(n);
poly c=getln(n,b);
for(int i=0;i<n;i++)
{
c[i]=(a[i]-c[i]);
c[i]+=c[i]<0?mod:0;
}
c[0]++;
c[0]-=c[0]>=mod?mod:0;
return b*c;
}
inline poly operator ^(const poly &a,const ll b)
{
ll n=a.size();
poly c=getln(n,a);
for(int i=0;i<n;i++)
c[i]*=b,c[i]%=mod;
return getexp(n,c);
}
signed main()
{
ll n,m;
read(n);
read(m);
poly a,b;
a.resize(n+1);
b.resize(m+1);
for(int i=0;i<=n;i++)
read(a[i]);
for(int i=0;i<=m;i++)
read(b[i]);
poly c=a*b;
for(int i=0;i<=n+m;i++)
printf("%lld ",c[i]);
putchar('\n');
exit(0);
}

多项式多点求值

#include<bits/stdc++.h>
#define N 2001001
#define MAX 2001
using namespace std;
typedef long long ll;
typedef double db;
const ll inf=1e18,mod=998244353,inv3=(mod+1)/3;
inline void read(ll &ret)
{
ret=0;char c=getchar();bool pd=false;
while(!isdigit(c)){pd|=c=='-';c=getchar();}
while(isdigit(c)){ret=(ret<<1)+(ret<<3)+
(c&15);c=getchar();}
ret=pd?-ret:ret;
return;
}
ll n,a[N],res[N],f[N],m,ls[N],rs[N],g[N],ans[N];
inline ll qpow(ll a,ll b)
{
ll ret=1;
while(b)
{
if(b&1)
ret*=a,ret%=mod;
b>>=1;
a*=a;
a%=mod;
}
return ret;
}
ll rev[N];
inline void ntt(ll a[],ll n,ll inv)
{
ll num=1,bit=0;
while(num<n)
{
num<<=1;
bit++;
}
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 Wn=qpow(inv==1?3:inv3,(mod-1)/(mid<<1));
for(int i=0;i<n;i+=mid<<1)
{
ll w=1;
for(int j=0;j<mid;j++,w*=Wn,w%=mod)
{
ll x=a[i+j],y=w*a[i+j+mid]%mod;
a[i+j]=x+y,a[i+j+mid]=x-y;
a[i+j]-=a[i+j]>=mod?mod:0;
a[i+j+mid]+=a[i+j+mid]<0?mod:0;
}
}
}
return;
}
inline void mul(ll a[],ll n,ll b[],ll m)
{
ll num=1;
while(num<(n+m))
num<<=1;
ntt(a,num,1);
ntt(b,num,1);
for(int i=0;i<num;i++)
a[i]*=b[i],a[i]%=mod;
ntt(a,num,-1);
ntt(b,num,-1);
ll inv=qpow(num,mod-2);
for(int i=n+m;i<num;i++)
a[i]=0;
for(int i=m;i<num;i++)
b[i]=0;
for(int i=0;i<n+m;i++)
a[i]*=inv,a[i]%=mod;
for(int i=0;i<m;i++)
b[i]*=inv,b[i]%=mod;
return;
}
inline void mult(ll a[],ll n,ll b[],ll m)
{
ll num=1;
while(num<(n+m))
num<<=1;
reverse(a,a+num);
ntt(a,num,1);
ntt(b,num,1);
for(int i=0;i<num;i++)
a[i]*=b[i],a[i]%=mod;
ntt(a,num,-1);
// ntt(b,num,-1);
reverse(a,a+num);
ll inv=qpow(num,mod-2);
for(int i=n+m;i<num;i++)
a[i]=0;
/* for(int i=m;i<num;i++)
b[i]=0;*/
for(int i=0;i<n+m;i++)
a[i]*=inv,a[i]%=mod;
/* for(int i=0;i<m;i++)
b[i]*=inv,b[i]%=mod;*/
return;
}
inline ll up(ll num)
{
ll x=1;
while(x<num)
x<<=1;
return x;
}
inline void solve(ll n,ll a[])
{
if(n==1)
{
res[0]=qpow(a[0],mod-2);
return;
}
ll *b=new ll[n-n/2];
for(int i=0;i<n-n/2;i++)
b[i]=a[i];
solve(n-n/2,b);
ll len=up(n+n-n/2+n-n/2);
ll *t=new ll[len],*tmp=new ll[len];
memset(t,0,len*sizeof(ll));
memset(tmp,0,len*sizeof(ll));
for(int i=0;i<n;i++)
t[i]=a[i],tmp[i]=res[i],res[i]*=2,res[i]%=mod;
mul(t,n,tmp,n-n/2);
mul(t,n+(n-n/2),tmp,n-n/2);
for(int i=0;i<n;i++)
{
res[i]-=t[i];
if(res[i]<0)
res[i]+=mod;
}
return;
}
ll tot;
vector<ll>v[N],G[N];
inline ll work(ll l,ll r)
{
tot++;
if(l==r)
{
v[tot].push_back(1);
v[tot].push_back(mod-a[l]);
return tot;
}
ll mid=l+r>>1;
ll pos=tot;
ls[pos]=work(l,mid);
rs[pos]=work(mid+1,r);
ll *a=new ll[up(mid-l+2+r-mid+1)],*b=new ll[up(mid-l+2+r-
mid+1)];
memset(a,0,up(mid-l+2+r-mid+1)*sizeof(ll));
memset(b,0,up(mid-l+2+r-mid+1)*sizeof(ll));
for(int j=0;j<=mid-l+1;j++)
a[j]=v[ls[pos]][j];
for(int j=0;j<=r-mid;j++)
b[j]=v[rs[pos]][j];
mul(a,mid-l+2,b,r-mid+1);
for(int i=0;i<=r-l+1;i++)
v[pos].push_back(a[i]);
return pos;
}
ll cnt=0;
inline void calc(ll l,ll r)
{
cnt++;
if(l==r)
{
ans[l]=G[cnt][0];
return;
}
ll mid=l+r>>1;
ll *a=new ll[up((r-l+1)*2)],*b=new ll[up((r-
l+1)*2)],*c=new ll[up((r-l+1)*2)];
memset(a,0,up((r-l+1)*2)*sizeof(ll));
memset(b,0,up((r-l+1)*2)*sizeof(ll));
memset(c,0,up((r-l+1)*2)*sizeof(ll));
for(int i=0;i<r-l+1;i++)
a[i]=G[cnt][i];
for(int i=0;i<=mid-l+1;i++)
b[i]=v[ls[cnt]][i];
for(int i=0;i<=r-mid;i++)
c[i]=v[rs[cnt]][i];
mult(a,r-l+1,b,mid-l+2);
for(int i=0;i<r-mid;i++)
G[rs[cnt]].push_back(a[i]);
memset(a,0,up((r-l+1)*2)*sizeof(ll));
for(int i=0;i<r-l+1;i++)
a[i]=G[cnt][i];
mult(a,r-l+1,c,r-mid+1);
for(int i=0;i<mid-l+1;i++)
G[ls[cnt]].push_back(a[i]);
calc(l,mid);
calc(mid+1,r);
return;
}
signed main()
{
// freopen("P5050_1.in","r",stdin);
// freopen("x.out","w",stdout);
read(n);
n++;
read(m);
for(int i=0;i<n;i++)
read(f[i]);
for(int i=1;i<=m;i++)
read(a[i]);
work(1,m);
cerr<<clock()*1.0/CLOCKS_PER_SEC<<endl;
for(int i=0;i<=m;i++)
g[i]=v[1][i];
solve(n,g);
mult(f,n,res,m+1);
cerr<<clock()*1.0/CLOCKS_PER_SEC<<endl;
for(int i=0;i<m;i++)
G[1].push_back(f[i]);
calc(1,m);
cerr<<clock()*1.0/CLOCKS_PER_SEC<<endl;
for(int i=1;i<=m;i++)
printf("%lld\n",ans[i]);
exit(0);
}

快速插值

#include<bits/stdc++.h>
#define N 2001001
#define MAX 2001
using namespace std;
typedef int ll;
typedef double db;
const ll inf=2e9,mod=998244353,inv3=(mod+1)/3;
inline void read(ll &ret)
{
ret=0;char c=getchar();bool pd=false;
while(!isdigit(c)){pd|=c=='-';c=getchar();}
while(isdigit(c)){ret=(ret<<1)+(ret<<3)+
(c&15);c=getchar();}
ret=pd?-ret:ret;
return;
}
ll n,res[N],f[N],m,ls[N],rs[N],g[N],ans[N];
inline ll qpow(ll a,ll b)
{
ll ret=1;
while(b)
{
if(b&1)
ret=1ll*ret*a%mod;
b>>=1;
a=1ll*a*a%mod;
}
return ret;
}
ll *w[N][2];
ll *rev[N];
inline void ntt(ll a[],ll n,ll inv)
{
for(int i=0;i<n;i++)
{
if(i<rev[n][i])
swap(a[i],a[rev[n][i]]);
}
for(int mid=1;mid<n;mid<<=1)
{
for(int i=0;i<n;i+=mid<<1)
{
for(int j=0;j<mid;j++)
{
ll x=a[i+j],y=1ll*w[mid][inv==1?0:1]
[j]*a[i+j+mid]%mod;
a[i+j]=x+y,a[i+j+mid]=x-y;
a[i+j]-=a[i+j]>=mod?mod:0;
a[i+j+mid]+=a[i+j+mid]<0?mod:0;
}
}
}
return;
}
ll tempa[N],tempb[N];
ll cc[N];
bool vis[N];
inline void mul(ll a[],ll n,ll b[],ll m)
{
ll num=1,bit=0;
while(num<(n+m))
num<<=1,bit++;
if(!vis[num])
{
vis[num]=true;
rev[num]=new ll[num];
rev[num][0]=0;
for(int i=0;i<num;i++)
rev[num][i]=(rev[num][i>>1]>>1)|((i&1)<<bit-1);
}
for(int i=0;i<m;i++)
tempb[i]=b[i];
for(int i=0;i<n;i++)
tempa[i]=a[i];
ntt(a,num,1);
ntt(b,num,1);
for(int i=0;i<num;i++)
cc[i]=1ll*a[i]*b[i]%mod;
ntt(cc,num,-1);
ll inv=qpow(num,mod-2);
for(int i=n;i<num;i++)
a[i]=0;
for(int i=m;i<num;i++)
b[i]=0;
for(int i=0;i<n+m;i++)
cc[i]=1ll*cc[i]*inv%mod;
for(int i=0;i<m;i++)
b[i]=tempb[i];
for(int i=0;i<n;i++)
a[i]=tempa[i];
return;
}
inline void mult(ll a[],ll n,ll b[],ll m)
{
ll num=1,bit=0;
while(num<(n+m))
num<<=1,bit++;
if(!vis[num])
{
vis[num]=true;
rev[num]=new ll[num];
rev[num][0]=0;
for(int i=0;i<num;i++)
rev[num][i]=(rev[num][i>>1]>>1)|((i&1)<<bit-1);
}
for(int i=0;i<m;i++)
tempb[i]=b[i];
for(int i=0;i<n;i++)
tempa[i]=a[i];
reverse(a,a+num);
ntt(a,num,1);
ntt(b,num,1);
for(int i=0;i<num;i++)
cc[i]=1ll*a[i]*b[i]%mod;
ntt(cc,num,-1);
// ntt(b,num,-1);
reverse(cc,cc+num);
ll inv=qpow(num,mod-2);
for(int i=n;i<num;i++)
a[i]=0;
for(int i=m;i<num;i++)
b[i]=0;
for(int i=0;i<n+m;i++)
cc[i]=1ll*cc[i]*inv%mod;
for(int i=0;i<m;i++)
b[i]=tempb[i];
for(int i=0;i<n;i++)
a[i]=tempa[i];
return;
}
inline ll up(ll num)
{
ll x=1;
while(x<num)
x<<=1;
return x;
}
ll a[N],b[N],c[N];
ll t[N],tp[N];
inline void solve(ll n,ll a[])
{
if(n==1)
{
res[0]=qpow(a[0],mod-2);
return;
}
solve(n-n/2,a);
ll len=up(n+n-n/2+n-n/2);
for(int i=0;i<n;i++)
{
t[i]=a[i],tp[i]=res[i],res[i]*=2;
if(res[i]>=mod)
res[i]-=mod;
}
ll num=1,bit=0;
while(num<len)
num<<=1,bit++;
if(!vis[num])
{
vis[num]=true;
rev[num]=new ll[num];
rev[num][0]=0;
for(int i=0;i<num;i++)
rev[num][i]=(rev[num][i>>1]>>1)|((i&1)<<bit-1);
}
ntt(t,num,1);
ntt(tp,num,1);
for(int i=0;i<num;i++)
t[i]=1ll*t[i]*tp[i]%mod*tp[i]%mod;
ntt(t,num,-1);
ll inv=qpow(num,mod-2);
for(int i=0;i<num;i++)
t[i]=1ll*inv*t[i]%mod;
for(int i=0;i<n;i++)
{
res[i]-=t[i];
if(res[i]<0)
res[i]+=mod;
}
for(int i=0;i<len;i++)
t[i]=tp[i]=0;
return;
}
ll tot;
ll x[N],y[N];
ll *v[N],*G[N];
inline ll work(ll l,ll r)
{
tot++;
if(l==r)
{
v[tot]=new ll[8];
memset(v[tot],0,8*sizeof(ll));
v[tot][0]=1,v[tot][1]=mod-x[l];
return tot;
}
ll mid=l+r>>1;
ll pos=tot;
ls[pos]=work(l,mid);
rs[pos]=work(mid+1,r);
mul(v[ls[pos]],mid-l+2,v[rs[pos]],r-mid+1);
v[pos]=new ll[up((r-l+2)*3+5)];
memset(v[pos],0,up((r-l+2)*3+5)*sizeof(ll));
for(int i=0;i<=r-l+1;i++)
v[pos][i]=cc[i];
return pos;
}
ll cnt=0;
inline void calc(ll l,ll r)
{
cnt++;
if(l==r)
{
ans[l]=G[cnt][0];
return;
}
ll mid=l+r>>1;
mult(G[cnt],r-l+1,v[ls[cnt]],mid-l+2);
G[rs[cnt]]=new ll[up((r-mid)*2)];
memset(G[rs[cnt]],0,up((r-mid)*2)*sizeof(ll));
for(int i=0;i<r-mid;i++)
G[rs[cnt]][i]=cc[i];
mult(G[cnt],r-l+1,v[rs[cnt]],r-mid+1);
G[ls[cnt]]=new ll[up((mid-l+1)*2)];
memset(G[ls[cnt]],0,up((mid-l+1)*2)*sizeof(ll));
for(int i=0;i<mid-l+1;i++)
G[ls[cnt]][i]=cc[i];
calc(l,mid);
calc(mid+1,r);
return;
}
vector<ll>vv[N],gg[N];
inline ll mywork(ll l,ll r)
{
tot++;
if(l==r)
{
vv[tot].push_back(mod-x[l]);
vv[tot].push_back(1);
return tot;
}
ll mid=l+r>>1;
ll pos=tot;
ls[pos]=mywork(l,mid);
rs[pos]=mywork(mid+1,r);
memset(a,0,up(mid-l+2+r-mid+1)*sizeof(ll));
memset(b,0,up(mid-l+2+r-mid+1)*sizeof(ll));
for(int j=0;j<=mid-l+1;j++)
a[j]=vv[ls[pos]][j];
for(int j=0;j<=r-mid;j++)
b[j]=vv[rs[pos]][j];
mul(a,mid-l+2,b,r-mid+1);
for(int i=0;i<=r-l+1;i++)
vv[pos].push_back(cc[i]);
return pos;
}
ll tmp[N];
inline void mysolve(ll l,ll r)
{
tot++;
if(l==r)
{
// cout<<l<<" "<<y[l]*qpow(ans[l],mod-2)%mod<<endl;
gg[tot].push_back(1ll*y[l]*qpow(ans[l],mod-2)%mod);
return;
}
ll pos=tot;
ll mid=l+r>>1;
mysolve(l,mid);
mysolve(mid+1,r);
memset(a,0,up(r-l+2)*sizeof(ll));
memset(b,0,up(r-l+2)*sizeof(ll));
memset(c,0,up(r-l+2)*sizeof(ll));
for(int i=0;i<=r-mid;i++)
a[i]=vv[rs[pos]][i];
for(int i=0;i<mid-l+1;i++)
b[i]=gg[ls[pos]][i];
mul(a,r-mid+1,b,mid-l+1);
for(int i=0;i<=r-l+1;i++)
a[i]=cc[i];
memset(b,0,up(r-l+2)*sizeof(ll));
for(int i=0;i<=mid-l+1;i++)
c[i]=vv[ls[pos]][i];
for(int i=0;i<r-mid;i++)
b[i]=gg[rs[pos]][i];
mul(c,mid-l+2,b,r-mid);
for(int i=0;i<r-l+1;i++)
{
a[i]+=cc[i];
if(a[i]>=mod)
a[i]-=mod;
gg[pos].push_back(a[i]);
}
return;
}
signed main()
{
// freopen("test3.in","r",stdin);
// freopen("x.out","w",stdout);
read(n);
// n++;
for(int i=1;i<=n;i++)
{
read(x[i]);
read(y[i]);
}
for(int mid=1;mid<(1<<19);mid<<=1)
{
ll Wn=qpow(3,(mod-1)/(mid<<1));
ll now=1;
w[mid][0]=new ll[mid];
for(int j=0;j<mid;j++,now=1ll*now*Wn%mod)
w[mid][0][j]=now;
Wn=qpow(inv3,(mod-1)/(mid<<1));
now=1;
w[mid][1]=new ll[mid];
for(int j=0;j<mid;j++,now=1ll*now*Wn%mod)
w[mid][1][j]=now;
}
mywork(1,n);
for(int i=0;i<n;i++)
f[i]=1ll*vv[1][i+1]*(i+1)%mod,tmp[i]=f[i];
tot=0;
work(1,n);
for(int i=0;i<=n;i++)
g[i]=v[1][i];
solve(n,g);
/* cerr<<clock()*1.0/CLOCKS_PER_SEC<<endl;
for(int i=0;i<n;i++)
cout<<res[i]<<" ";
cout<<endl;*/
mult(f,n,res,n);
G[1]=new ll[up(n*3+5)];
memset(G[1],0,up(n*3+5)*sizeof(ll));
for(int i=0;i<n;i++)
G[1][i]=cc[i];
calc(1,n);
/* for(int i=1;i<=n;i++)
cout<<ans[i]<<" ";
cout<<endl;*/
tot=0;
mysolve(1,n);
for(int i=0;i<n;i++)
printf("%d ",gg[1][i]);
putchar('\n');
//cerr<<clock()*1.0/CLOCKS_PER_SEC<<endl;
exit(0);
}

mtt(任意模数)

#include<bits/stdc++.h>
#define N 2001001
#define re register
#define MAX 2001
#define eps 1e-10
using namespace std;
typedef long long ll;
typedef double db;
const ll mod1=998244353,mod2=1004535809, mod3=469762049,g=3;
inline void read(re ll &ret)
{
ret=0;re bool pd=false;re char c=getchar();
while(!isdigit(c)){(c=='-')&&(pd=true);c=getchar();}
while(isdigit(c)){ret=(ret<<1)+(ret<<3)+
(c^48);c=getchar();}
ret=pd?-ret:ret;
return;
}
ll
n,m,p,a[N],b[N],ans1[N],ans2[N],ans3[N],num,rev[N],inv1g,inv2g
,inv3g,aa[N],bb[N];
inline ll qpow(re ll a,re ll b,re ll p)
{
re ll ret=1;
while(b)
{
if(b&1)
ret*=a,ret%=p;
b>>=1;
a*=a;
a%=p;
}
return ret%p;
}
inline ll inv(re ll x,re ll p)
{
return qpow(x,p-2,p);
}
inline void ntt1(re ll a[],re ll n,re ll typ)
{
re ll num=1,bit=0;
while(num<n)
{
num<<=1;
bit++;
}
for(re 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(re int mid=1;mid<n;mid<<=1)
{
re ll wn=qpow((typ==1)?g:inv1g,(mod1-
1)/(mid<<1),mod1);
for(re int j=0;j<n;j+=mid<<1)
{
re ll w=1;
for(re int i=0;i<mid;i++,w*=wn,w%=mod1)
{
re ll x=a[i+j],y=a[i+j+mid]*w%mod1;
a[i+j]=(x+y)%mod1,a[i+j+mid]=(x-y+mod1)%mod1;
}
}
}
return;
}
inline void ntt2(re ll a[],re ll n,re ll typ)
{
re ll num=1,bit=0;
while(num<n)
{
num<<=1;
bit++;
}
for(re 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(re int mid=1;mid<n;mid<<=1)
{
re ll wn=qpow((typ==1)?g:inv2g,(mod2-
1)/(mid<<1),mod2);
for(re int j=0;j<n;j+=mid<<1)
{
re ll w=1;
for(re int i=0;i<mid;i++,w*=wn,w%=mod2)
{
re ll x=a[i+j],y=a[i+j+mid]*w%mod2;
a[i+j]=(x+y)%mod2,a[i+j+mid]=(x-y+mod2)%mod2;
}
}
}
return;
}
inline void ntt3(re ll a[],re ll n,re ll typ)
{
re ll num=1,bit=0;
while(num<n)
{
num<<=1;
bit++;
}
for(re 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(re int mid=1;mid<n;mid<<=1)
{
re ll wn=qpow((typ==1)?g:inv3g,(mod3-
1)/(mid<<1),mod3);
for(re int j=0;j<n;j+=mid<<1)
{
re ll w=1;
for(re int i=0;i<mid;i++,w*=wn,w%=mod3)
{
re ll x=a[i+j],y=a[i+j+mid]*w%mod3;
a[i+j]=(x+y)%mod3,a[i+j+mid]=(x-y+mod3)%mod3;
}
}
}
return;
}
inline void solve1()
{
ntt1(a,num,1);
ntt1(b,num,1);
for(re int i=0;i<num;i++)
ans1[i]=a[i]*b[i]%mod1;
ntt1(ans1,num,-1);
memcpy(a,aa,(num+1)*sizeof(ll));
memcpy(b,bb,(num+1)*sizeof(ll));
return;
}
inline void solve2()
{
ntt2(a,num,1);
ntt2(b,num,1);
for(re int i=0;i<num;i++)
ans2[i]=a[i]*b[i]%mod2;
ntt2(ans2,num,-1);
memcpy(a,aa,(num+1)*sizeof(ll));
memcpy(b,bb,(num+1)*sizeof(ll));
return;
}
inline void solve3()
{
ntt3(a,num,1);
ntt3(b,num,1);
for(re int i=0;i<num;i++)
ans3[i]=a[i]*b[i]%mod3;
ntt3(ans3,num,-1);
memcpy(a,aa,(num+1)*sizeof(ll));
memcpy(b,bb,(num+1)*sizeof(ll));
return;
}
int main()
{
inv1g=inv(g,mod1);
inv2g=inv(g,mod2);
inv3g=inv(g,mod3);
read(n);
read(m);
read(p);
for(re int i=0;i<=n;i++)
read(a[i]);
for(re int i=0;i<=m;i++)
read(b[i]);
num=1;
while(num<n+m+1)
num<<=1;
memcpy(aa,a,(num+1)*sizeof(ll));
memcpy(bb,b,(num+1)*sizeof(ll));
solve1();
solve2();
solve3();
for(re int i=0;i<n+m+1;i++)
{
re ll
x1=ans1[i]*inv(num,mod1)%mod1,x2=ans2[i]*inv(num,mod2)%mod2,x3
=ans3[i]*inv(num,mod3)%mod3;
re ll k1,k2,k3;
k1=((x2-x1)%mod2+mod2)%mod2*inv(mod1,mod2)%mod2;
re ll x4=x1+k1*mod1;
re ll k4=((x3-
x4%mod3)%mod3+mod3)%mod3*inv(mod1,mod3)%mod3*inv(mod2,mod3)%mo
d3;
if(i)
putchar(' ');
printf("%lld",(x4%p+(k4%p)*(mod1*mod2%p)%p)%p);
}
putchar('\n');
exit(0);
}

多项式开根
#include<bits/stdc++.h>
#define N 2001001
#define MAX 2001
using namespace std;
typedef long long ll;
typedef double db;
const ll inf=1e18,mod=998244353,inv3=(mod+1)/3;
inline void read(ll &ret)
{
ret=0;char c=getchar();bool pd=false;
while(!isdigit(c)){pd|=c=='-';c=getchar();}
while(isdigit(c)){ret=(ret<<1)+(ret<<3)+
(c&15);c=getchar();}
ret=pd?-ret:ret;
return;
}
ll n,a[N],res[N],ans[N];
inline ll qpow(ll a,ll b)
{
ll ret=1;
while(b)
{
if(b&1)
ret*=a,ret%=mod;
b>>=1;
a*=a;
a%=mod;
}
return ret;
}
ll rev[N];
inline void ntt(ll a[],ll n,ll inv)
{
ll num=1,bit=0;
while(num<n)
{
num<<=1;
bit++;
}
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 Wn=qpow(inv==1?3:inv3,(mod-1)/(mid<<1));
for(int i=0;i<n;i+=mid<<1)
{
ll w=1;
for(int j=0;j<mid;j++,w*=Wn,w%=mod)
{
ll x=a[i+j],y=w*a[i+j+mid]%mod;
a[i+j]=x+y,a[i+j+mid]=x-y;
if(a[i+j]>=mod)
a[i+j]-=mod;
if(a[i+j+mid]<0)
a[i+j+mid]+=mod;
}
}
}
return;
}
ll temp[N];
inline void mul(ll a[],ll n,ll b[],ll m)
{
ll num=1;
while(num<(n+m))
num<<=1;
for(int i=0;i<m;i++)
temp[i]=b[i];
ntt(a,num,1);
ntt(b,num,1);
for(int i=0;i<num;i++)
a[i]*=b[i],a[i]%=mod;
ntt(a,num,-1);
//ntt(b,num,-1);
ll inv=qpow(num,mod-2);
for(int i=n+m;i<num;i++)
a[i]=0;
for(int i=0;i<m;i++)
b[i]=temp[i];
for(int i=m;i<num;i++)
b[i]=0;
for(int i=0;i<n+m;i++)
a[i]*=inv,a[i]%=mod;
return;
}
ll now;
struct node
{
ll x,y;
};
inline node operator *(node x,node y)
{
return node{(x.x*y.x%mod+now*x.y%mod*y.y%mod)%mod,
(x.y*y.x%mod+x.x*y.y%mod)%mod};
}
inline ll qqpow(node a,ll b,ll p)
{
node ret=a;
b--;
if(!b)
return 1;
while(b)
{
if(b&1)
ret=ret*a;
b>>=1;
a=a*a;
}
return ret.x;
}
inline bool check(ll x)
{
return qpow(x,(mod-1)>>1)==1;
}
ll ms;
inline void calc(ll n,ll p)
{
if(!n)
{
puts("0");
return;
}
if(!check(n))
{
puts("Hola!");
return;
}
ll tmp=rand();
tmp=tmp*tmp%p*tmp%p;
while(!tmp||check((tmp*tmp%p-n%p+p)%p))
{
tmp=rand();
tmp=tmp*tmp%p*tmp%p;
}
now=(tmp*tmp%p-n%p+p)%p;
ll x=qqpow(node{tmp,1},(p+1)>>1,p);
ll y=(-x+p)%p;
if(x!=y)
ms=min(x,y);
else
ms=x;
return;
}
inline ll up(ll num)
{
ll x=1;
while(x<num)
x<<=1;
return x;
}
inline void solve(ll n,ll a[])
{
if(n==1)
{
res[0]=qpow(a[0],mod-2);
return;
}
ll *b=new ll[n-n/2];
for(int i=0;i<n-n/2;i++)
b[i]=a[i];
solve(n-n/2,b);
ll len=up(n+n-n/2+n-n/2);
ll *t=new ll[len],*tmp=new ll[len];
memset(t,0,len*sizeof(ll));
memset(tmp,0,len*sizeof(ll));
for(int i=0;i<n;i++)
t[i]=a[i],tmp[i]=res[i],res[i]*=2,res[i]%=mod;
mul(t,n,tmp,n-n/2);
mul(t,n+(n-n/2),tmp,n-n/2);
for(int i=0;i<n;i++)
{
res[i]-=t[i];
if(res[i]<0)
res[i]+=mod;
}
return;
}
ll tmp[N];
inline void work(ll n,ll a[])
{
if(n==1)
{
calc(a[0],mod);
ans[0]=ms;
return;
}
ll *b=new ll[n-n/2];
memset(b,0,(n-n/2)*sizeof(b));
for(int i=0;i<n-n/2;i++)
b[i]=a[i];
work(n-n/2,b);
ll len=up((n-n/2)+(n-n/2));
for(int i=0;i<len;i++)
tmp[i]=0;
for(int i=0;i<n-n/2;i++)
tmp[i]=ans[i];
mul(ans,n-n/2,tmp,n-n/2);
for(int i=n;i<len;i++)
ans[i]=0;
for(int i=0;i<n;i++)
ans[i]+=a[i],ans[i]%=mod;
for(int i=0;i<n-n/2;i++)
tmp[i]*=2,tmp[i]%=mod;
len=up(n+n);
solve(n,tmp);
for(int i=n;i<len;i++)
res[i]=0;
mul(ans,n,res,n);
for(int i=n;i<len;i++)
ans[i]=0;
for(int i=0;i<len;i++)
res[i]=0;
return;
}
signed main()
{
read(n);
for(int i=0;i<n;i++)
read(a[i]);
work(n,a);
for(int i=0;i<n;i++)
printf("%lld ",ans[i]);
putchar('\n');
exit(0);
}

复数 FFT

#include<bits/stdc++.h>
#define eps 1e-7
#define re register
#define N 5001001
#define MAX 2001
#define PI acos(-1)
#define inf 1e18
using namespace std;
typedef long long ll;
typedef double db;
inline void read(re ll &ret)
{
ret=0;re ll pd=0;re char c=getchar();
while(!isdigit(c)){pd|=c=='-';c=getchar();}
while(isdigit(c)){ret=(ret<<1)+(ret<<3)+
(c^48);c=getchar();}
ret=pd?-ret:ret;
}
ll n,m,num,rev[N];
complex<db> a[N],b[N];
inline void fft(re complex<db> a[],re ll n,re ll inv)
{
re ll bit=0;
while((1<<bit)<n)
bit++;
for(re 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(re int mid=1;mid<n;mid<<=1)
{
re complex<db> Wn(cos(PI/mid),inv*sin(PI/mid));
for(re int i=0;i<n;i+=mid<<1)
{
re complex<db> w(1,0);
for(re int j=0;j<mid;j++,w=w*Wn)
{
re complex<db> x=a[i+j],y=w*a[i+j+mid];
a[i+j]=x+y,a[i+j+mid]=x-y;
}
}
}
return;
}
int main()
{
read(n);
read(m);
for(re int i=0;i<=n;i++)
{
re ll tmp;
read(tmp);
a[i]=tmp;
}
for(re int i=0;i<=m;i++)
{
re ll tmp;
read(tmp);
b[i]=tmp;
}
num=1;
while(num<=n+m)num<<=1;
fft(a,num,1),fft(b,num,1);
for(re int i=0;i<num;i++)
a[i]*=b[i];
fft(a,num,-1);
for(re int i=0;i<=n+m;i++)
{
if(i)
putchar(' ');
printf("%d",ll(a[i].real()/num+0.5));
}
putchar('\n');
exit(0);
}

分治 NTT

#include<bits/stdc++.h>
#define N 2001001
#define MAX 2001
#define inf 1e18
using namespace std;
typedef long long ll;
typedef double db;
const ll mod=998244353,inv3=332748118;
inline void read(ll &ret)
{
ret=0;ll pd=0;char c=getchar();
while(!isdigit(c)){pd|=c=='-';c=getchar();}
while(isdigit(c)){ret=(ret<<1)+(ret<<3)+
(c^48);c=getchar();}
ret=pd?-ret:ret;
return;
}
ll n,g[N],f[N],a[N],b[N];
ll m;
ll rev[N];
inline ll qpow(ll a,ll b)
{
ll ret=1;
while(b)
{
if(b&1)
ret*=a,ret%=mod;
b>>=1;
a*=a;
a%=mod;
}
return ret;
}
inline void ntt(ll a[],ll n,ll inv)
{
ll bit=0,now=1;
while(now<n)
{
now<<=1;
bit++;
}
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 len=1;len<n;len<<=1)
{
ll Wn=qpow((inv==1?3:inv3),(mod-1)/(len<<1));
for(int i=0;i<n;i+=len<<1)
{
ll w=1;
for(int j=0;j<len;j++,w*=Wn,w%=mod)
{
ll x=a[i+j],y=w*a[i+j+len]%mod;
a[i+j]=x+y;
if(a[i+j]>=mod)
a[i+j]-=mod;
a[i+j+len]=x-y;
if(a[i+j+len]<0)
a[i+j+len]+=mod;
}
}
}
return;
}
inline void work(ll l,ll r)
{
if(l==r)
return;
ll mid=l+r>>1;
work(l,mid);
for(int j=l;j<=mid;j++)
a[j-l]=f[j],b[j-l]=g[j-l];
for(int j=mid+1;j<=r;j++)
a[j-l]=0,b[j-l]=g[j-l];
for(int i=r-l+1;i<((r-l+1)<<1);i++)
a[i]=b[i]=0;
ntt(a,(r-l+1)<<1,1);
ntt(b,(r-l+1)<<1,1);
for(int j=0;j<((r-l+1)<<1);j++)
a[j]*=b[j],a[j]%=mod;
ntt(a,(r-l+1)<<1,-1);
ll inv=qpow((r-l+1)<<1,mod-2);
for(int j=mid+1;j<=r;j++)
{
f[j]+=a[j-l]*inv%mod;
if(f[j]>=mod)
f[j]-=mod;
}
work(mid+1,r);
return;
}
int main()
{
read(n);
m=n;
for(int i=1;i<n;i++)
read(g[i]);
ll now=1,cnt=0;
while(now<n)
now<<=1;
n=now;
f[0]=1;
work(0,n-1);
for(int i=0;i<m;i++)
{
if(i)
putchar(' ');
printf("%lld",f[i]);
}
putchar('\n');
exit(0);
}

【2】数学相关

原根
有原根的数: ,其中 为奇素数, 为正整数。

怎么求一个数 n 的所有原根?

首先找到 n 的最小原根,设为 g,则 n 的所有原根可以由 g 的若干次乘方得


到。

具体地,若 n 存在原根,则其原根个数为 ,每一个原根都形如


的形式,要求满足 gcd⁡(k,φ(n))=1。
如何得到 n 的最小原根?枚举即可。

根据原根的定义,如果 g 是 n 的原根,除了满足 g^φ(n)≡1(mod n) 外,还需


要满足对于任意更小的 k 有 g^k≠1。而我们不可能把小于 φ(n) 的所有数都
拿出来检验。

事实上,关于阶有一条强的性质:如果 gcd⁡(a,n)=1,且 a^k≡1 mod n,则


k∣φ(n),所以我们事实上只需要检验 φ(n) 的所有真因子即可。

于是我们可以在 O(n0.25log⁡n)。

#include <bits/stdc++.h>
using namespace std;
const int MAXN=1000010;
int
t,p,cnt,tot,ctans,fc[MAXN],ans[MAXN],pri[MAXN],rt[MAXN],q[MAXN
],phi[MAXN];
void init () {
phi[1]=1;
for (int i=2;i<=MAXN-10;i++) {
if (!q[i]) {pri[++tot]=i,phi[i]=i-1;}
for (int j=1;j<=tot&&pri[j]*i<=MAXN-10;j++) {
q[i*pri[j]]=1;
if (i%pri[j]==0) {
phi[i*pri[j]]=phi[i]*pri[j];
break;
}
phi[i*pri[j]]=phi[i]*(pri[j]-1);
}
}
rt[2]=rt[4]=1;
for (int i=2;i<=tot;i++) {
for (int j=1;(1ll*j*pri[i])<=MAXN-10;j*=pri[i])
{rt[j*pri[i]]=1;}
for (int j=2;(1ll*j*pri[i])<=MAXN-10;j*=pri[i])
{rt[j*pri[i]]=1;}
}
return;
}
int gcd (int a,int b) {return (b==0?a:gcd(b,a%b));}
int qpow (int a,int b,int p) {
int res=1;
while (b) {
if (b&1) {res=(1ll*res*a)%p;}
a=(1ll*a*a)%p;
b>>=1;
}
return res;
}
void proc (int p) {
for (int i=2;i*i<=p;i++) {
if (p%i==0) {
fc[++cnt]=i;
while (p%i==0) {p/=i;}
}
}
if (p>1) {fc[++cnt]=p;}
return;
}
bool chk (int x,int p) {
if (qpow(x,phi[p],p)!=1) {return 0;}
for (int i=1;i<=cnt;i++) {
if (qpow(x,phi[p]/fc[i],p)==1) {return 0;}
}
return 1;
}
int findrt (int p) {
for (int i=1;i<p;i++) {
if (chk(i,p)) {return i;}
}
return 0;
}
void getrt (int p,int x) {
int prod=1;
for (int i=1;i<=phi[p];i++) {
prod=(1ll*prod*x)%p;
if (gcd(i,phi[p])==1) {
ans[++ctans]=prod;
}
}
return;
}
int main () {
init();
scanf("%d",&t);
for (int ii=1;ii<=t;ii++) {
int wtf;
scanf("%d%d",&p,&wtf);
if (rt[p]) {
ctans=cnt=0;
proc(phi[p]);
int mn=findrt(p);
getrt(p,mn);
sort(ans+1,ans+ctans+1);
printf("%d\n",ctans);
for (int i=1;i<=ctans/wtf;i++) {printf("%d
",ans[i*wtf]);}
printf("\n");
} else {
printf("0\n\n");
}
}
return 0;
}

Pollard-Rho

#include<bits/stdc++.h>
typedef long long LL;
typedef unsigned long long ULL;
#define rep(i, s, t) for(int i = (s); i <= (t); i ++)
#define per(i, s, t) for(int i = (s); i >= (t); i --)
#define Ede(i, u) for(int i = head[u]; i; i = e[i].nxt)
using namespace std;

LL read() {
LL x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') f = (c == '-') ? -1 : 1, c =
getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - 48, c =
getchar();
return x * f;
}

LL Gcd(LL a, LL b) {while(b) {LL c = a; a = b, b = c % b;}


return a;}

LL Mul(ULL a, ULL b, ULL p) {return (__int128) a * b % p;}

LL Pow(LL a, LL b, LL p) {
LL s = 1;
for(; b; b >>= 1) {
if(b & 1) s = Mul(s, a, p);
a = Mul(a, a, p);
}
return s;
}

int p[] = {2, 3, 5, 7, 11, 13, 43};

bool Miller_Rabin(LL a) {
if(a <= 2) return a == 2;
LL t = a - 1, k = 0;
while(! (t & 1)) t >>= 1, k ++;
rep(o, 0, 6) {
if(a == p[o]) return true;
LL cur = Pow(p[o], t, a), nxt;
rep(i, 1, k) {
nxt = Mul(cur, cur, a);
if(nxt == 1 && cur != 1 && cur != a - 1) return
false;
cur = nxt;
}
if(cur != 1) return false;
}
return true;
}

mt19937 Rand(20060814);
LL Abs(LL x) {return x < 0 ? - x : x;}

LL Rho(LL n) {
while(true) {
LL x = Rand() % n, y = x;
LL c = Rand() % n, z = 1;
int s = 0, t = 1;
while(++ s) {
x = Mul(x, x, n) + c; if(x >= n) x -= n;
z = Mul(z, Abs(y - x), n);
if(! z) break;
if(! (s & 127) || s == t) {
LL d = Gcd(n, z);
if(d > 1) return d;
if(s == t) y = x, t <<= 1;
}
}
}
}

LL ans;

void Pollard(LL n) {
if(n <= ans) return;
if(Miller_Rabin(n)) {ans = n; return;}
LL d = Rho(n);
while(n % d == 0) n /= d;
Pollard(n), Pollard(d);
}

int main() {
int T = read();
while(T --) {
LL n = read();
if(Miller_Rabin(n)) {puts("Prime"); continue;}
ans = 1, Pollard(n);
printf("%lld\n", ans);
}
return 0;
}

矩阵树、LGV、BEST
Matrix-Tree 定理:

对于无向图:

有度数矩阵 : , ,邻接矩阵 ,得到矩阵


那么该无根树的生成树个数等于, 矩阵任意 阶主子式的


对于有向图:

删除的主子式的行列编号即为根 。

为入度矩阵,则对应外向树, 。

为出度矩阵,则对应内向树, 。

还有与之相关的两个定理:

定理:

有向欧拉图 的欧拉回路计数 :

其中 是任选的。

引理:

对于有向无环图 ,每条边有权值 (计数的话令 即


可)。

定义 表示路径 的权值。

现给定起点集合 和终点集合 ,满足 且


设 表示 与 之间,所有路径 的权值之和,构造矩阵:
那么有 。

其中 表示 对应到 ,每条对应路径都不相交的方案数。

对于网格图,这就是 的方案数(否则一定有交)。

否则,它的组合意义是,把图画在一个平面上并且将起点集合和终
点集合从上自下一字排开,

就是存在 偶数个交点的路径组条数 减去 存在奇数个交点


的路径组条数。

注意这还是不相交路径,只是作为逆序对的另一种叙述。

筛法
杜教筛

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<unordered_map>
using namespace std;

typedef long long LL;


#define PII pair<LL, int>
#define MP make_pair
const int M = 1700000;
int n, tot, prm[M + 10], mu[M + 10];
LL phi[M + 10]; bool vis[M + 10];
unordered_map<int, LL> Phi;
unordered_map<int, int> Mu;

int read(){
int x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') f = (c == '-') ? -1 : 1, c =
getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - 48, c =
getchar();
return x * f;
}

void Pre(){
phi[1] = mu[1] = 1;
for(int i = 2; i <= M; i ++){
if(!vis[i]){
prm[++ tot] = i;
phi[i] = i - 1; mu[i] = -1;
}
for(int j = 1; j <= tot && prm[j] * i <= M; j ++){
vis[prm[j] * i] = true;
if(i % prm[j]){
phi[prm[j] * i] = phi[i] * (prm[j] - 1);
mu[prm[j] * i] = - mu[i];
}
else{
phi[prm[j] * i] = phi[i] * prm[j];
mu[prm[j] * i] = 0;
break;
}
}
phi[i] += phi[i - 1];
mu[i] += mu[i - 1];
}
}

PII Get(LL x){


if(x <= M) return MP(phi[x], mu[x]);
if(Phi[x]) return MP(Phi[x], Mu[x]);
LL a = 1LL * x * (x + 1LL) / 2LL;
LL b = 1;
for(LL l = 2, r; l <= x; l = r + 1){
r = min(x / (x / l), x);
PII now = Get(x / l);
a -= 1LL * (r - l + 1) * now.first;
b -= 1LL * (r - l + 1) * now.second;
}
Phi[x] = a, Mu[x] = b;
return MP(a, b);
}

int main(){
int T = read();
Pre();
while(T --){
n = read();
PII ans = Get(n);
printf("%lld %d\n", ans.first, ans.second);
}
return 0;
}

Min-25

求 ,其中 是一个积性函数,且 。

假设我们要求一个 ,满足 是一个积性函数,且 是个


关于 的低阶多项式。

因为多项式可以拆成若干个单项式,所以我们只需要考虑求出 的
前缀和,然后每一项加起来就行了。

那么如何求出每一项的和呢?

Step1 分类

让我们先对i i 按照质数和合数分类:

然后,我们枚举后面合数的最小质因子以及最小质因子的次数。注意所有合
数的最小质因子一定都小于等于 :

其中minp表示i的最小质因子,因为公式中文太丑了所以就只好写英文了。
这样,整个式子就变成了两个部分,第一部分是所有质数的f之和,另一部
分是枚举最小质因子后,求所有最小质因子大于这个质因子的f之和。

Step2 第一部分

由于n实在太大,所以我们没法用线性筛求出所有质数的f和。

我们考虑一个DP的思路(天哪这是怎么想到的):我们不知道从哪里找来
了一个DP数组g(n,i),满足

这里的k就是前面我们说的低阶多项式的一项。注意 并不是我们要求的 ,
只是一个和f在质数处的取值一样的完全积性函数,这样后面计算起来比较
方便。

这个式子说人话就是g(n,j)表示求1到n之间所有满足条件的数的k次方和,条
件就是要么是质数要么最小质因子大于pj。

我们考虑 如何转移到 。随着j的增大,满足条件的数变少


了,所以我们需要减去一些原来满足条件而现在不满足条件的数。

这些数应该是最小质因子恰好为 的合数。

我们可以提出来一个 作为最小质因子,这样剩下的就不能有小于它的质因
子了,也就是 ,后面那个g是为了把所有的质数去

掉。

这样我们就得到了g的递推式:

完全积性函数的好处在这里就体现出来了:由于只提出了一个 ,所以后面
还有可能有 这个因子,如果是完全积性函数的话就可以将函数值直接相
乘,而不用管是否互质。

注意到后面的 其实就是前 个质数的k次方和。由于


,所以这一部分可以用线性筛预处理,我们设 ,也
就是前 n 个质数的 k 次方和。
1到n中所有质数的k次方和其实就是g(n,x),其中 是最后一个小于等于
的质数。为了方便,我们把它记作g(n)。

但是因为n太大,我们还是没法对于每一个n求出g(n,x),所以我们可以想到
另一个重要的结论:

也就是说,无论你每一次把n除以几,最后你能得到的数一定是某一个
,所以我们没必要算出来所有的n,只需要算出可以写成 这种形式的
数,这样的数一共有 个。

那么我们如何存储这 个数呢?

首先我们不能直接下标访问,这样下标可以到n。我们需要对下标离散化。

但是离散化之后,我们还需要知道对于每一个 ,它对应的下标是什
么。

如果偷懒的话可以用map,但是时间复杂度会多一个log⁡。我们可以用
ind1[x] 表示x这个数对应的数组下标,ind2[x]表示n/x这个数对应的下标。这
样两个ind数组最大都只会到 。

具体实现可以看代码。数组的记录上需要精细实现一下。

Step2 求解答案

答案就是先求出所有质数的函数和,然后先枚举了一个 ,再枚举最小质
因子大于p 的数。

我们还是可以考虑DP的思想。设S(n,x)表示求1到n中所有最小质因子大于
的函数值之和,注意这里是f而不是k次方。答案就是S(n,0)。

我们将满足条件的数分成两部分,第一部分是大于 的质数,也就是
,另一部分是最小质因子大于 的合数,枚举最小质因子:

这样问题就解决了,我们可以递归求解这个问题。根据某玄学定理,不需要
记忆化。
#include<bits/stdc++.h>
#define re register
#define N 201001
#define MAX 2001
#define inf 1e18
using namespace std;
typedef long long ll;
typedef double db;
const ll mod=1000000007,inv3=333333336;
inline void read(re ll &ret)
{
ret=0;re bool pd=false;re char c=getchar();
while(!isdigit(c)){pd|=c=='-';c=getchar();}
while(isdigit(c)){ret=(ret<<1)+(ret<<3)+
(c&15);c=getchar();}
ret=pd?-ret:ret;
return;
}
ll n;
bool prime[N];
ll p[N],tot,sp[2][N],g[2][N],ind[2][N],w[N],cnt;
inline void init(re ll n)
{
for(re ll i=2;i*i<=n;i++)
prime[i]=true;
for(re ll i=2;i*i<=n;i++)
{
if(prime[i])
p[++tot]=i,sp[0][tot]=(sp[0][tot-
1]+p[tot])%mod,sp[1][tot]=(sp[1][tot-
1]+p[tot]*p[tot]%mod)%mod;
for(re ll j=1;j<=tot&&p[j]*i*p[j]*i<=n;j++)
{
prime[p[j]*i]=false;
if(!(i%p[j]))
break;
}
}
return;
}
inline ll s(re ll x,re ll j)
{
if(p[j]>=x)
return 0;
re ll k=(n/x>=x)?ind[0][x]:ind[1][n/x];
re ll ans=(g[1][k]-g[0][k]+mod-(sp[1][j]-sp[0]
[j])+mod)%mod;
for(re ll i=j+1;i<=tot&&p[i]*p[i]<=x;i++)
for(re ll tmp=1,num=p[i];num<=x;tmp++,num*=p[i])
ans+=num%mod*((num-1)%mod)%mod*(s(x/num,i)+
(tmp!=1))%mod,ans%=mod;
ans=(ans+mod)%mod;
return ans;
}
signed main()
{
read(n);
init(n);
for(re ll i=1,j;i<=n;i=j+1)
{
j=n/(n/i);
w[++cnt]=n/i;
if(n/w[cnt]>=w[cnt])
ind[0][w[cnt]]=cnt;
else
ind[1][n/w[cnt]]=cnt;
g[0][cnt]=w[cnt]%mod;
g[1][cnt]=g[0][cnt]*(g[0][cnt]+1)/2%mod*((g[0][cnt]
<<1)+1)%mod*inv3%mod;
g[1][cnt]=(g[1][cnt]-1+mod)%mod;
g[0][cnt]=((g[0][cnt]+1)*g[0][cnt]/2-1)%mod;
}
for(re ll i=1;i<=tot;i++)
{
for(re ll j=1;j<=cnt&&p[i]*p[i]<=w[j];j++)
{
re ll tmp=w[j]/p[i];
re ll k=(n/tmp>=tmp)?ind[0][tmp]:ind[1][n/tmp];
g[0][j]-=p[i]*(g[0][k]-sp[0][i-1]+mod)%mod;
g[1][j]-=p[i]*p[i]%mod*(g[1][k]-sp[1][i-
1]+mod)%mod;
g[0][j]=(g[0][j]+mod)%mod;
g[1][j]=(g[1][j]+mod)%mod;
}
}
printf("%lld\n",(s(n,0)+1)%mod);
exit(0);
}

子集卷积
给定两个长度为 的序列 和 ,你需要求
出一个序列 ,其中 满足:

其中 表示按位或, 表示按位与。

#include<bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;
#define rep(i, a, b) for(int i = (a); i <= (b); i ++)
#define per(i, a, b) for(int i = (a); i >= (b); i --)
#define Ede(i, u) for(int i = head[u]; i; i = e[i].nxt)
using namespace std;

const int P = 1e9 + 9;


inline int plu(int x, int y) {return x + y >= P ? x + y - P :
x + y;}
inline int del(int x, int y) {return x - y < 0 ? x - y + P :
x - y;}
inline void add(int &x, int y) {x = plu(x, y);}
inline void sub(int &x, int y) {x = del(x, y);}
inline int qpow(int a, int b) {int s = 1; for(; b; b >>= 1, a
= 1ll * a * a % P) if(b & 1) s = 1ll * s * a % P; return s;}

inline int read() {


int x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') f = (c == '-') ? - 1 : 1, c =
getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - 48, c =
getchar();
return x * f;
}

int n, a[21][1 << 20], b[21][1 << 20], f[21][1 << 20];

void fwt(int *f, int opt) {


for(int o = 2, k = 1; o <= (1 << n); o <<= 1, k <<= 1)
for(int i = 0; i < (1 << n); i += o) rep(j, 0, k - 1)
if(opt) add(f[i + j + k], f[i + j]); else sub(f[i
+ j + k], f[i + j]);
}

int main() {
n = read();
rep(i, 0, (1 << n) - 1) a[__builtin_popcount(i)][i] =
read();
rep(i, 0, (1 << n) - 1) b[__builtin_popcount(i)][i] =
read();

rep(i, 0, n) fwt(a[i], 1), fwt(b[i], 1);


rep(i, 0, n) {
rep(j, 0, i) rep(s, 0, (1 << n) - 1)
add(f[i][s], 1ll * a[j][s] * b[i - j][s] % P);
fwt(f[i], 0);
}
rep(i, 0, (1 << n) - 1) printf("%d%c",
f[__builtin_popcount(i)][i], i == ((1 << n) - 1) ? '\n' : '
');
return 0;
}

exBSGS

#include<bits/stdc++.h>
#define rep(i, s, t) for(int i = (s); i <= (t); i ++)
#define per(i, s, t) for(int i = (s); i >= (t); i --)
using namespace std;

#define int long long

int read() {
int x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') f = (c == '-') ? -1 : 1, c =
getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - 48, c =
getchar();
return x * f;
}

int Gcd(int a, int b) {while(b) {int c = a; a = b, b = c % b;}


return a;}

int exGcd(int a, int b, int &x, int &y) {


if(! b) {x = 1, y = 0; return a;}
int d = exGcd(b, a % b, x, y);
int z = x; x = y, y = z - a / b * y;
return d;
}

int Inv(int a, int p) {


int x, y;
exGcd(a, p, x, y);
return (x % p + p) % p;
}

int Pow(int a, int b, int p) {


int s = 1;
for(; b; b >>= 1) {
if(b & 1) s = 1LL * s * a % p;
a = 1LL * a * a % p;
}
return s;
}
int BSGS(int a, int b, int p) {
map<int, int> hash;
a %= p, b %= p;
int t = sqrt(p) + 1, c = Pow(a, t, p), d = 1;
rep(i, 1, t) {
d = 1LL * d * c % p;
if(hash.find(d) == hash.end()) hash[d] = i;
}
int ans = 1e15;
rep(i, 0, t) {
if(hash.find(b) != hash.end()) ans = min(ans, t *
hash[b] - i);
b = 1LL * b * a % p;
}
return (ans == 1e15) ? -1 : ans;
}

int exBSGS(int a, int b, int p) {


a %= p, b %= p;
if(1 % p == b % p) return 0;
int d, D = 1, c = 0;
while((d = Gcd(a, p)) > 1) {
if(b % d != 0) return - 1;
b /= d, p /= d;
D = 1LL * D * (a / d) % p, c ++;
if(D == b) return c;
}
b = 1LL * b * Inv(D, p) % p;
int ans = BSGS(a, b, p);
if(ans == -1) return -1;
return ans + c;
}

signed main() {
while(true) {
int a = read(), p = read(), b = read();
if(! a) break;
int ans = exBSGS(a, b, p);
if(ans == - 1) puts("No Solution"); else
printf("%d\n", ans);
}
return 0;
}

二次剩余

// Problem: P5491 【模板】二次剩余


// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P5491
// Memory Limit: 125 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;
#define rep(i, a, b) for(int i = (a); i <= (b); i ++)
#define per(i, a, b) for(int i = (a); i >= (b); i --)
#define Ede(i, u) for(int i = head[u]; i; i = e[i].nxt)
using namespace std;

typedef pair<ll, ll> pll;


#define mp make_pair
#define fi first
#define se second

inline ll read() {
ll x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') f = (c == '-') ? - 1 : 1, c =
getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - 48, c =
getchar();
return x * f;
}

mt19937_64 myrand(19260817);
ll p, val;
ll qpow(ll a, ll b) {
ll s = 1;
for(; b; b >>= 1, a = a * a % p) if(b & 1) s = s * a % p;
return s;
}

pll mul(pll a, pll b) {


return mp((a.fi * b.fi % p + val * a.se % p * b.se % p) %
p,
(a.fi * b.se % p + a.se * b.fi % p) % p);
}

pll qpow(pll a, ll b) {
pll s = mp(1, 0);
for(; b; b >>= 1, a = mul(a, a)) if(b & 1) s = mul(s, a);
return s;
}

bool check(ll x) {
return (qpow(x, (p - 1) >> 1) == 1);
}

pll solve(int n, ll p_) {


p = p_;
if(! check(n)) return mp(-1, -1);
ll a = myrand() % p;
while(a == 0 || check((a * a - n + p) % p)) a = myrand() %
p;
val = (a * a - n + p) % p;
ll x0 = qpow(mp(a, 1), (p + 1) >> 1).fi, x1 = p - x0;
if(x0 > x1) swap(x0, x1);
return mp(x0, x1);
}

int main() {
int t = read();
while(t --) {
ll n = read(), p = read();
if(! n) {puts("0"); continue;}
pll ans = solve(n, p);
if(ans.fi == -1) {puts("Hola!"); continue;}
printf("%lld %lld\n", ans.fi, ans.se);
}
return 0;
}

Lucas 定理与 ExLucas

#include<bits/stdc++.h>
#define rep(i, s, t) for(int i = (s); i <= (t); i ++)
#define per(i, s, t) for(int i = (s); i >= (t); i --)
using namespace std;

const int N = 1e5 + 10;


int p, fac[N], inv[N];

int read() {
int x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') f = (c == '-') ? -1 : 1, c =
getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - 48, c =
getchar();
return x * f;
}

int Pow(int a, int b) {


int s = 1;
for(; b; b >>= 1) {
if(b & 1) s = 1LL * s * a % p;
a = 1LL * a * a % p;
}
return s;
}

int C(int n, int m) {


if(n < m) return 0;
return 1LL * fac[n] * inv[m] % p * inv[n - m] % p;
}
int Lucas(int n, int m) {
if(! m) return 1;
return 1LL * Lucas(n / p, m / p) * C(n % p, m % p) % p;
}

void Work() {
int n = read(), m = read(); p = read();
fac[0] = inv[0] = 1;
rep(i, 1, p - 1)
fac[i] = 1LL * fac[i - 1] * i % p;
inv[p - 1] = Pow(fac[p - 1], p - 2);
per(i, p - 2, 1)
inv[i] = 1LL * inv[i + 1] * (i + 1) % p;
printf("%d\n", Lucas(n + m, n));
}

int main() {
int T = read();
while(T --) Work();
return 0;
}

Ex

#include<bits/stdc++.h>
typedef long long LL;
#define rep(i, s, t) for(int i = (s); i <= (t); i ++)
#define per(i, s, t) for(int i = (s); i >= (t); i --)
using namespace std;

LL Pow(LL a, LL b, LL p) {
LL s = 1;
for(; b; b >>= 1) {
if(b & 1) s = 1LL * s * a % p;
a = 1LL * a * a % p;
}
return s;
}

LL exGcd(LL a, LL b, LL &x, LL &y) {


if(! b) {x = 1, y = 0; return a;}
LL d = exGcd(b, a % b, x, y);
LL z = x; x = y, y = z - a / b * y;
return d;
}

LL Inv(LL a, LL p) {
LL x, y;
exGcd(a, p, x, y);
return (x % p + p) % p;
}

int cnt;
LL a[100], b[100];

LL CRT() {
LL M = 1, ans = 0;
rep(i, 1, cnt) M *= b[i];
rep(i, 1, cnt) {
LL Mi = M / b[i], x, y;
exGcd(Mi, b[i], x, y);
ans = (ans + Mi * x % M * a[i] % M) % M;
}
return (ans % M + M) % M;
}

LL Calc(LL n, LL p, LL P) {
if(! n) return 1;
LL mul = 1;
for(int i = 1; i <= P; i ++) if(i % p) mul = mul * i % P;
mul = Pow(mul, n / P, P);
for(LL i = n / P * P + 1; i <= n; i ++) if(i % p) mul = i
% P * mul % P;
return mul * Calc(n / p, p, P) % P;
}

LL multiLucas(LL n, LL m, LL p, LL P) {
LL cnt = 0;
for(LL i = n; i; i /= p) cnt += i / p;
for(LL i = m; i; i /= p) cnt -= i / p;
for(LL i = n - m; i; i /= p) cnt -= i / p;
return Pow(p, cnt, P) * Calc(n, p, P) % P
* Inv(Calc(m, p, P), P) % P * Inv(Calc(n - m, p, P),
P) % P;
}

LL exLucas(LL n, LL m, LL p) {
cnt = 0;
for(LL i = 2; i * i <= p; i ++)
if(p % i == 0) {
b[++ cnt] = 1;
while(p % i == 0) b[cnt] *= i, p /= i;
a[cnt] = multiLucas(n, m, i, b[cnt]);
}
if(p > 1)
b[++ cnt] = p, a[cnt] = multiLucas(n, m, p, p);
return CRT();
}

int main() {
LL n, m, p;
scanf("%lld %lld %lld", &n, &m, &p);
printf("%lld\n", exLucas(n, m, p));
return 0;
}

exCRT

#include<bits/stdc++.h>
#define rep(i, s, t) for(int i = (s); i <= (t); i ++)
#define per(i, s, t) for(int i = (s); i >= (t); i --)
using namespace std;

typedef long long LL;

LL read() {
LL x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') f = (c == '-') ? -1 : 1, c =
getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - 48, c =
getchar();
return x * f;
}

LL Mul(LL a, LL b, LL p) {
a = (a % p + p) % p;
b = (b % p + p) % p;
unsigned long long c = (long double) a / p * b;
unsigned long long d = a * b - c * p;
if(d < 0) return d + p;
if(d >= p) return d - p;
return d;
}

LL exGcd(LL a, LL b, LL &x, LL &y) {


if(! b) {x = 1, y = 0; return a;}
LL d = exGcd(b, a % b, x, y);
LL z = x; x = y, y = z - y * (a / b);
return d;
}

int main() {
int n = read();
LL M = 1, ans = 0;
rep(i, 1, n) {
LL b = read(), a = read();
a = ((a - ans) % b + b) % b;
LL x, y, d = exGcd(M, b, x, y);
LL M0 = M; M = M / d * b;
x = Mul(x, a / d, M);
ans = (ans + Mul(M0, x, M)) % M;
}
printf("%lld\n", (ans % M + M) % M);
return 0;
}

FWT
#include<bits/stdc++.h>
typedef long long LL;
#define rep(i, a, b) for(int i = (a); i <= (b); i ++)
#define per(i, a, b) for(int i = (a); i >= (b); i --)
#define Ede(i, u) for(int i = head[u]; i; i = e[i].nxt)
using namespace std;

int read() {
int x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') f = (c == '-') ? - 1 : 1, c =
getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - 48, c =
getchar();
return x * f;
}

const int N = (1 << 17) + 10;


const int P = 998244353;
const int inv2 = 499122177;
int n, A[N], B[N];

int plu(int x, int y) {return x + y >= P ? x + y - P : x + y;}


int del(int x, int y) {return x - y < 0 ? x - y + P : x - y;}
void add(int &x, int y) {if((x += y) >= P) x -= P;}
void sub(int &x, int y) {if((x -= y) < 0) x += P;}

int a[N], b[N], c[N];

void Init() {rep(i, 0, n - 1) a[i] = A[i], b[i] = B[i];}

void AND(int *f, int x) {


for(int o = 2, k = 1; o <= n; o <<= 1, k <<= 1)
for(int i = 0; i < n; i += o) rep(j, 0, k - 1)
if(x) add(f[i + j + k], f[i + j]); else sub(f[i +
j + k], f[i + j]);
}

void OR(int *f, int x) {


for(int o = 2, k = 1; o <= n; o <<= 1, k <<= 1)
for(int i = 0; i < n; i += o) rep(j, 0, k - 1)
if(x) add(f[i + j], f[i + j + k]); else sub(f[i +
j], f[i + j + k]);
}

void XOR(int *f, int x) {


for(int o = 2, k = 1; o <= n; o <<= 1, k <<= 1)
for(int i = 0; i < n; i += o) rep(j, 0, k - 1) {
int A = f[i + j], B = f[i + j + k];
f[i + j ] = 1LL * x * plu(A, B) % P;
f[i + j + k] = 1LL * x * del(A, B) % P;
}
}

void Mul() {rep(i, 0, n - 1) c[i] = 1LL * a[i] * b[i] % P;}

void Print() {rep(i, 0, n - 1) printf("%d ", c[i]); puts("");}

int main() {
n = read(), n = (1 << n);
rep(i, 0, n - 1) A[i] = read();
rep(i, 0, n - 1) B[i] = read();
Init(), AND(a, 1), AND(b, 1), Mul(), AND(c, 0), Print();
Init(), OR(a, 1), OR(b, 1), Mul(), OR(c, 0), Print();
Init(), XOR(a, 1), XOR(b, 1), Mul(), XOR(c, inv2),
Print();
return 0;
}

【3】图论相关

2-SAT

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#define N 2000010
using namespace std;

int n,m,head[N],cnt=0;
struct Edge{
int nxt,to;
}ed[N<<1];

int read(){
int x=0,f=1;char c=getchar();
while(c<'0' || c>'9') f=(c=='-')?-1:1,c=getchar();
while(c>='0' && c<='9') x=x*10+c-48,c=getchar();
return x*f;
}

void add(int x,int y){


ed[++cnt].nxt=head[x];
ed[cnt].to=y;
head[x]=cnt;
return;
}

int dfn[N],col[N],low[N],s[N],tot=0,color=0,tim=0;

void Tarjan(int u){


dfn[u]=low[u]=++tim;
s[++tot]=u;
for(int i=head[u];i;i=ed[i].nxt){
int v=ed[i].to;
if(!dfn[v]) Tarjan(v),low[u]=min(low[u],low[v]);
else if(!col[v]) low[u]=min(low[u],dfn[v]);
}
if(low[u]==dfn[u]){
col[u]=++color;
while(u!=s[tot])
col[s[tot]]=color,--tot;
--tot;
}
return;
}
int main(){
n=read(),m=read();
for(int i=1;i<=m;i++){
int x=read(),a=read(),y=read(),b=read();
add(x+n*(a&1),y+n*(b^1));
add(y+n*(b&1),x+n*(a^1));
}
for(int i=1;i<=(n<<1);i++)
if(!dfn[i]) Tarjan(i);
for(int i=1;i<=n;i++)
if(col[i]==col[i+n]){
puts("IMPOSSIBLE");return 0;
}
puts("POSSIBLE");
for(int i=1;i<=n;i++){
if(col[i]<col[i+n]) printf("1 ");
else printf("0 ");
}
return 0;
}

Prufer 序列

#include<bits/stdc++.h>
typedef long long LL;
#define rep(i, s, t) for(int i = (s); i <= (t); i ++)
#define per(i, s, t) for(int i = (s); i >= (t); i --)
#define Ede(i, u) for(int i = head[u]; i; i = e[i].nxt)
using namespace std;

const int N = 5e6 + 10;


int n, m, a[N], f[N], d[N];

int read() {
int x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') f = (c == '-') ? - 1 : 1, c =
getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - 48, c =
getchar();
return x * f;
}

void TP() {
rep(i, 1, n - 1) f[i] = read(), d[f[i]] ++;
for(int i = 1, j = 1; i <= n - 2; i ++, j ++) {
while(d[j]) j ++; a[i] = f[j];
while(i < n - 2 && ! -- d[a[i]] && a[i] < j) a[i + 1]
= f[a[i]], i ++;
}
LL ans = 0;
rep(i, 1, n - 2) ans ^= 1LL * i * a[i];
printf("%lld\n", ans);
}

void PT() {
rep(i, 1, n - 2) a[i] = read(), d[a[i]] ++;
a[n - 1] = n;
for(int i = 1, j = 1; i <= n - 1; i ++, j ++) {
while(d[j]) j ++; f[j] = a[i];
while(i < n - 1 && ! -- d[a[i]] && a[i] < j) f[a[i]] =
a[i + 1], i ++;
}
LL ans = 0;
rep(i, 1, n - 1) ans ^= 1LL * i * f[i];
printf("%lld\n", ans);
}

int main() {
n = read(), m = read();
if(m == 1) TP(); else PT();
return 0;
}

支配树

#include<bits/stdc++.h>
#define N 501001
#define MAX 2005
using namespace std;
typedef long long ll;
typedef double db;
const ll mod=998244353,inf=1e18;
inline void read(ll &ret)
{
ret=0;char c=getchar();bool pd=false;
while(!isdigit(c)){pd|=c=='-';c=getchar();}
while(isdigit(c)){ret=(ret<<1)+(ret<<3)+
(c&15);c=getchar();}
ret=pd?-ret:ret;
return;
}
ll n,m,x,y,dfn[N],cnt,semi[N],idom[N],nd[N];
ll fat[N];
vector<ll>v[N],g[N],h[N];
inline void tarjan(ll ver)
{
dfn[ver]=++cnt;
nd[cnt]=ver;
for(int i=0;i<v[ver].size();i++)
{
ll to=v[ver][i];
if(!dfn[to])
{
tarjan(to);
fat[to]=ver;
}
}
return;
}
ll fa[N],minn[N];
inline ll find(ll deep)
{
if(fa[deep]==deep)
return deep;
ll tmp=find(fa[deep]);
if(dfn[semi[minn[deep]]]>dfn[semi[minn[fa[deep]]]])
minn[deep]=minn[fa[deep]];
fa[deep]=tmp;
return tmp;
}
ll ans[N];
signed main()
{
// freopen("P5180_6.in","r",stdin);
// freopen("2.out","w",stdout);
read(n);
read(m);
for(int i=1;i<=m;i++)
{
read(x);
read(y);
v[x].push_back(y);
g[y].push_back(x);
}
/* for(int i=1;i<=n;i++)
{
reverse(v[i].begin(),v[i].end());
reverse(g[i].begin(),g[i].end());
}*/
tarjan(1);
for(int i=1;i<=n;i++)
{
semi[i]=fa[i]=i;
minn[i]=i;
}
for(int i=cnt;i>1;i--)
{
ll ver=nd[i];
for(auto to:g[ver])
{
if(!dfn[to])
continue;
if(dfn[to]==dfn[ver])
continue;
find(to);
if(dfn[semi[minn[to]]]<dfn[semi[ver]])
semi[ver]=semi[minn[to]];
}
h[semi[ver]].push_back(ver);
find(ver);
for(auto to:h[ver])
{
find(to);
if(ver==semi[minn[to]])
idom[to]=ver;
else
idom[to]=minn[to];
}
for(auto to:v[ver])
{
if(fat[to]==ver)
{
fa[find(to)]=find(ver);
find(to);
}
}
}
for(auto to:h[1])
{
find(to);
if(1==semi[minn[to]])
idom[to]=1;
else
idom[to]=minn[to];
}
for(int i=2;i<=cnt;i++)
{
ll ver=nd[i];
if(idom[ver]!=semi[ver])
idom[ver]=idom[idom[ver]];
}
for(int i=1;i<=cnt;i++)
ans[nd[i]]=1;
for(int i=cnt;i>=2;i--)
ans[idom[nd[i]]]+=ans[nd[i]];
for(int i=1;i<=n;i++)
printf("%lld ",ans[i]);
exit(0);
}

欧拉路径

#include<bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;
#define rep(i, a, b) for(int i = (a); i <= (b); i ++)
#define per(i, a, b) for(int i = (a); i >= (b); i --)
#define Ede(i, u) for(int i = head[u]; i; i = e[i].nxt)
using namespace std;

#define eb emplace_back

inline int read() {


int x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') f = (c == '-') ? - 1 : 1, c =
getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - 48, c =
getchar();
return x * f;
}

const int N = 1e5 + 10;


int n, m, deg[N], cur[N];
vector<int> g[N], ans;

void dfs(int u) {
for(int &i = cur[u]; i < (int)g[u].size(); ) {
int v = g[u][i]; i ++;
dfs(v);
}
ans.eb(u);
}

int main() {
n = read(), m = read();
rep(i, 1, m) {int u = read(), v = read(); g[u].eb(v);
deg[u] ++, deg[v] --;}
int s = 0, t = 0;
rep(i, 1, n) {
if(deg[i] < -1 || deg[i] > 1) return puts("No"), 0;
if(deg[i] == 1) {if(!s) s = i; else return
puts("No"), 0;}
if(deg[i] == -1) {if(!t) t = i; else return
puts("No"), 0;}
}

if(!s && !t) s = t = 1;


if(!s || !t) return puts("No"), 0;

rep(i, 1, n) sort(g[i].begin(), g[i].end());


dfs(s);
reverse(ans.begin(), ans.end());
for(auto o : ans) printf("%d ", o);
return 0;
}

Dinic 与 费用流
Dinic

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;

const int INF = 1 << 30;


const int N = 1010;
const int M = N * N * 2;

int n, a[N], c[N], w[N][N];


int S, T, cnt = 1, head[N], now[N], d[N];
struct Edge{int nxt, to, val;} ed[M];
queue<int> q;
int read() {
int x = 0, f = 1; char c = getchar();
while (c < '0' || c > '9') f = (c == '-') ? -1 : 1, c =
getchar();
while (c >= '0' && c <= '9') x = x * 10 + c - 48, c =
getchar();
return x * f;
}

void add(int u, int v, int w){


ed[++ cnt] = (Edge){head[u], v, w}; head[u] = cnt;
ed[++ cnt] = (Edge){head[v], u, 0}; head[v] = cnt;
}

bool bfs(){
while(!q.empty()) q.pop();
memset(d, 0, sizeof(d));
d[S] = 1, now[S] = head[S]; q.push(S);
while(!q.empty()){
int u = q.front(); q.pop();
for(int i = head[u]; i; i = ed[i].nxt){
int v = ed[i].to, w = ed[i].val;
if(w && !d[v]){
d[v] = d[u] + 1;
now[v] = head[v];
if(v == T) return true;
q.push(v);
}
}
}
return false;
}

int Dinic(int u, int flow){


if(u == T) return flow;
int rest = flow; int i;
for(i = now[u]; i && rest; i = ed[i].nxt){
int v = ed[i].to, w = ed[i].val;
if(d[v] == d[u] + 1 && w){
int k = Dinic(v, min(rest, w));
if(!k) d[v] = 0;
ed[i].val -= k;
ed[i ^ 1].val += k;
rest -= k;
}
}
now[u] = i;
return flow - rest;
}

int Max_Flow(){
int Flow = 0, flow;
while(bfs())
while(flow = Dinic(S, INF)) Flow += flow;
return Flow;
}

最小费用最大流:

// Problem: #102. 最小费用流


// Contest: LibreOJ
// URL: https://loj.ac/p/102
// Memory Limit: 256 MB
// Time Limit: 4000 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
typedef long long ll;
#define rep(i, a, b) for(int i = (a); i <= (b); i ++)
#define per(i, a, b) for(int i = (a); i >= (b); i --)
#define Ede(i, u) for(int i = head[u]; i; i = e[i].nxt)
using namespace std;

#define mp make_pair
#define fi first
#define se second

inline int read() {


int x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') f = (c == '-') ? - 1 : 1, c =
getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - 48, c =
getchar();
return x * f;
}

const int N = 5e3 + 10, M = 1e5 + 10;


const int inf = 2147483647;
int n, m, s, t, head[N], cnt = 1;
struct edge {int nxt, v, w, c;} e[M];

void add(int u, int v, int w, int c) {


e[++ cnt] = (edge) {head[u], v, w, c}, head[u] = cnt;
e[++ cnt] = (edge) {head[v], u, 0, -c}, head[v] = cnt;
}

int h[N]; bool vis[N];

void prework() {
rep(i, 1, n) h[i] = inf;
queue<int> q; h[s] = 0, q.push(s);
while(! q.empty()) {
int u = q.front(); q.pop(), vis[u] = false;
Ede(i, u) {
int v = e[i].v, w = e[i].w, c = e[i].c;
if(w && h[v] > h[u] + c) {h[v] = h[u] + c; if(!
vis[v]) vis[v] = true, q.push(v);}
}
}
}

int dis[N], pre[N];

bool path() {
rep(i, 1, n) dis[i] = inf, vis[i] = false;
priority_queue<pair<int, int>> q; dis[s] = 0, q.push(mp(0,
s));
while(! q.empty()) {
int u = q.top().se; q.pop();
if(vis[u]) continue; vis[u] = true;
Ede(i, u) {
int v = e[i].v, w = e[i].w, c = e[i].c + h[u] -
h[v];
if(w && dis[v] > dis[u] + c) pre[v] = i, dis[v] =
dis[u] + c, q.push(mp(- dis[v], v));
}
}
return dis[t] != inf;
}

int main() {
n = read(), m = read(), s = read(), t = read();
rep(i, 1, m) {int u = read(), v = read(), w = read(), c =
read(); add(u, v, w, c);}
prework();
int ans1 = 0, ans2 = 0;
while(path()) {
rep(i, 1, n) h[i] += dis[i];
int flow = inf;
for(int i = t; i != s; i = e[pre[i] ^ 1].v) flow =
min(flow, e[pre[i]].w);
for(int i = t; i != s; i = e[pre[i] ^ 1].v)
e[pre[i]].w -= flow, e[pre[i] ^ 1].w += flow;
ans1 += flow;
ans2 += flow * h[t];
}
printf("%d %d\n", ans1, ans2);
return 0;
}

有负环的费用流

#include<bits/stdc++.h>
typedef long long LL;
#define rep(i, s, t) for(int i = (s); i <= (t); i ++)
#define per(i, s, t) for(int i = (s); i >= (t); i --)
#define Ede(i, u) for(int i = head[u]; i; i = e[i].nxt)
using namespace std;

const int N = 210, M = N * N;


const int INF = 1e9;
int n, m, s, t, Flow, Cost;
int cnt = 1, head[N];
struct Edge {int nxt, v, f, c;} e[M];

int read() {
int x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') f = (c == '-') ? - 1 : 1, c =
getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - 48, c =
getchar();
return x * f;
}

void Add(int u, int v, int f, int c) {


e[++ cnt] = (Edge) {head[u], v, f, c}, head[u] = cnt;
e[++ cnt] = (Edge) {head[v], u, 0, - c}, head[v] = cnt;
}

int dis[N], cur[N]; bool vis[N];

bool SPFA() {
rep(i, 1, n + 2) dis[i] = INF, cur[i] = head[i], vis[i] =
false;
queue<int> q; dis[s] = 0, q.push(s);
while(! q.empty()) {
int u = q.front(); q.pop();
vis[u] = false;
Ede(i, u) {
int v = e[i].v, c = e[i].c;
if(e[i].f && dis[v] > dis[u] + c) {
dis[v] = dis[u] + c;
if(! vis[v]) q.push(v), vis[v] = true;
}
}
}
return dis[t] < INF;
}

int Dinic(int u, int flow) {


if(u == t) return flow;
vis[u] = true;
int rest = flow;
for(int &i = cur[u]; i; i = e[i].nxt) {
int v = e[i].v, f = e[i].f, c = e[i].c;
if(! vis[v] && f && dis[v] == dis[u] + c) {
int k = Dinic(v, min(rest, f));
if(! k) dis[v] = - 1;
else
e[i].f -= k, e[i ^ 1].f += k, rest -= k, Cost
+= k * c;
if(! rest) break;
}
}
vis[u] = true;
return flow - rest;
}

void MCMF(int ss, int tt) {


s = ss, t = tt, Flow = Cost = 0;
int flow;
while(SPFA()) while(flow = Dinic(s, INF)) Flow += flow;
}

int d[N];

int main() {
n = read(), m = read();
int s0 = read(), t0 = read(), ans0 = 0, ans1 = 0;
rep(i, 1, m) {
int u = read(), v = read(), f = read(), c = read();
if(c >= 0)
Add(u, v, f, c);
else
Add(v, u, f, - c), d[u] -= f, d[v] += f, ans1 += f
* c;
}
int s1 = n + 1, t1 = s1 + 1;
rep(i, 1, n)
if(d[i] > 0) Add(s1, i, d[i], 0);
else Add(i, t1, - d[i], 0);

MCMF(s1, t1);
ans1 += Cost;
MCMF(s0, t0);
ans0 += Flow, ans1 += Cost;

printf("%d %d\n", ans0, ans1);


return 0;
}

割点

#include<bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;
#define rep(i, a, b) for(int i = (a); i <= (b); i ++)
#define per(i, a, b) for(int i = (a); i >= (b); i --)
#define Ede(i, u) for(int i = head[u]; i; i = e[i].nxt)
using namespace std;

#define eb emplace_back

inline int read() {


int x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') f = (c == '-') ? - 1 : 1, c =
getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - 48, c =
getchar();
return x * f;
}

const int N = 2e4 + 10;


int n, m; vector<int> g[N];

int tim, root, dfn[N], low[N]; bool cut[N];


void tarjan(int u) {
dfn[u] = low[u] = ++tim;
int num = 0;
for(auto v : g[u]) if(!dfn[v]) {
tarjan(v);
low[u] = min(low[u], low[v]);
if(low[v] == dfn[u]) num ++;
} else low[u] = min(low[u], dfn[v]);

cut[u] = (num > 1 || (num == 1 && root != u));


}

int main() {
n = read(), m = read();
rep(i, 1, m) {int u = read(), v = read(); g[u].eb(v),
g[v].eb(u);}
rep(i, 1, n) if(!dfn[i]) root = i, tarjan(i);

int s = 0;
rep(i, 1, n) s += cut[i];
printf("%d\n", s);
rep(i, 1, n) if(cut[i]) printf("%d ", i);
return 0;
}

最小树形图

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int N = 110;


const int M = 10010;
const int INF = 1 << 30;
int n, m, root, in[N], id[N], pre[N], vis[N];
struct Edge{int u, v, w;} e[M];

int read(){
int x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') f = (c == '-') ? -1 : 1, c =
getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - 48, c =
getchar();
return x * f;
}

int main(){
n = read(), m = read(), root = read();
for(int i = 1; i <= m; i ++)
e[i].u = read(), e[i].v = read(), e[i].w = read();
int ans = 0, u, v;
while(true){
for(int i = 1; i <= n; i ++) in[i] = INF;
for(int i = 1; i <= m; i ++){
u = e[i].u;
v = e[i].v;
if(u != v && in[v] > e[i].w){
in[v] = e[i].w;
pre[v] = u;
}
}
for(int i = 1; i <= n; i ++)
if(i != root && in[i] == INF){puts("-1"); return
0;}
int tot = 0;
for(int i = 1; i <= n; i ++) id[i] = vis[i] = -1;
in[root] = 0;
for(int i = 1; i <= n; i ++){
ans += in[i];
v = i;
while(vis[v] != i && v != root && id[v] == -1){
vis[v] = i;
v = pre[v];
}
if(v != root && id[v] == -1){
id[v] = ++ tot;
for(int u = pre[v]; u != v; u = pre[u]) id[u]
= tot;
}
}
if(!tot) break;
for(int i = 1; i <= n; i ++)
if(id[i] == -1) id[i] = ++ tot;
for(int i = 1; i <= m; i ++){
u = e[i].u;
v = e[i].v;
e[i].u = id[u];
e[i].v = id[v];
if(id[u] != id[v]) e[i].w -= in[v];
}
n = tot;
root = id[root];
}
printf("%d\n", ans);
return 0;
}

最小斯坦纳树
给定一个包含 个结点和 条带权边的无向连通图 。

再给定包含 个结点的点集 ,选出 的子图 ,使得:

1. ;

2. 为连通图;

3. 中所有边的权值和最小。

你只需要求出 中所有边的权值和。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;

typedef pair<int, int> P;


#define MP make_pair
const int N = 110;
const int M = 1 << 12;
const int INF = 0x3f3f3f3f;

int n, m, k, cnt, a[N], dis[N], head[N], f[N][M];


bool vis[N];
struct Edge{int nxt, to, val;} ed[1010];
priority_queue<P, vector<P>, greater<P> > q;

int read(){
int x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') f = (c == '-') ? -1 : 1, c =
getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - 48, c =
getchar();
return x * f;
}

void add(int u, int v, int w){


ed[++ cnt] = (Edge){head[u], v, w};
head[u] = cnt;
}

void Dijkstra(int S){


memset(vis, false, sizeof(vis));
while(!q.empty()){
int u = q.top().second; q.pop();
if(vis[u]) continue; vis[u] = true;
for(int i = head[u]; i; i = ed[i].nxt){
int v = ed[i].to, w = ed[i].val;
if(f[u][S] + w < f[v][S]){
f[v][S] = f[u][S] + w;
q.push(MP(f[v][S], v));
}
}
}
}

int main(){
n = read(), m = read(), k = read();
for(int i = 1; i <= m; i ++){
int u = read(), v = read(), w = read();
add(u, v, w), add(v, u, w);
}
memset(f, 0x3f, sizeof(f));
for(int i = 1; i <= k; i ++){
a[i] = read();
f[a[i]][1 << (i - 1)] = 0;
}
for(int S = 1; S < (1 << k); S ++){
for(int i = 1; i <= n; i ++){
for(int sub = S & (S - 1); sub; sub = S & (sub -
1))
f[i][S] = min(f[i][S], f[i][sub] + f[i][S ^
sub]);
if(f[i][S] != INF) q.push(MP(f[i][S], i));
}
Dijkstra(S);
}
printf("%d\n", f[a[1]][(1 << k) - 1]);
return 0;
}

边双

#include<bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;
#define rep(i, a, b) for(int i = (a); i <= (b); i ++)
#define per(i, a, b) for(int i = (a); i >= (b); i --)
#define Ede(i, u) for(int i = head[u]; i; i = e[i].nxt)
using namespace std;

#define eb emplace_back

inline int read() {


int x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') f = (c == '-') ? - 1 : 1, c =
getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - 48, c =
getchar();
return x * f;
}

const int N = 5e5 + 10;


const int M = 2e6 + 10;
int n, m, head[N], cnt = 1;
struct edge {int nxt, v;} e[M << 1];
bool bri[M << 1];

void add(int u, int v) {e[++ cnt] = (edge) {head[u], v},


head[u] = cnt;}

int tim, dfn[N], low[N];


void tarjan(int u, int lim) {
dfn[u] = low[u] = ++tim;
Ede(i, u) if(i != lim) {
int v = e[i].v;
if(!dfn[v]) {
tarjan(v, i ^ 1), 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]);
}
}

bool vis[N];
vector<int> cur;
vector<vector<int>> ans;

void dfs(int u) {
cur.eb(u), vis[u] = true;
Ede(i, u) if(!bri[i]) {int v = e[i].v; if(!vis[v])
dfs(v);}
}

int main() {
n = read(), m = read();
rep(i, 1, m) {int u = read(), v = read(); add(u, v),
add(v, u);}
rep(i, 1, n) if(!dfn[i]) tarjan(i, 0);
rep(i, 1, n) if(!vis[i]) {cur.clear(); dfs(i);
ans.eb(cur);}

printf("%d\n", (int)ans.size());
for(auto a : ans) {
printf("%d", (int) a.size());
for(auto b : a) printf(" %d", b);
putchar('\n');
}

return 0;
}

二分图最大匹配

#include<bits/stdc++.h>
typedef long long LL;
#define rep(i, a, b) for(int i = (a); i <= (b); i ++)
#define per(i, a, b) for(int i = (a); i >= (b); i --)
#define Ede(i, u) for(int i = head[u]; i; i = e[i].nxt)
using namespace std;

int read() {
int x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') f = (c == '-') ? - 1 : 1, c =
getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - 48, c =
getchar();
return x * f;
}

const int N = 510;


int n, m, e, g[N][N], mat[N];
bool vis[N];

bool dfs(int u) {
rep(v, 1, m) if(g[u][v] && ! vis[v]) {
vis[v] = true;
if(! mat[v] || dfs(mat[v]))
{mat[v] = u; return true;}
}
return false;
}

int main() {
n = read(), m = read(), e = read();
rep(i, 1, e) {
int u = read(), v = read();
g[u][v] = 1;
}
int ans = 0;
rep(s, 1, n) {
rep(i, 1, n) vis[i] = false;
ans += dfs(s);
}
printf("%d\n", ans);
return 0;
}

二分图最大权完美匹配

#include<bits/stdc++.h>
typedef long long LL;
#define rep(i, s, t) for(int i = (s); i <= (t); i ++)
#define per(i, s, t) for(int i = (s); i >= (t); i --)
#define Ede(i, u) for(int i = head[u]; i; i = e[i].nxt)
using namespace std;

const int N = 510;


const LL M = 19980731;
const LL INF = 1e12;
int n, m; LL g[N][N];

int read() {
int x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') f = (c == '-') ? -1 : 1, c =
getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - 48, c =
getchar();
return x * f;
}

int mx[N], my[N], pre[N];


LL lx[N], ly[N], slack[N];
bool vx[N], vy[N];

queue<int> q;

bool Path(int v) {
vy[v] = true;
if(my[v]) {q.push(my[v]), vx[my[v]] = true; return false;}
while(v) {my[v] = pre[v], swap(v, mx[pre[v]]);}
return true;
}

void Bfs(int s) {
while(! q.empty()) q.pop();
q.push(s), vx[s] = true;
while(true) {
while(! q.empty()) {
int u = q.front(); q.pop();
rep(v, 1, n) if(! vy[v]) {
LL cur = lx[u] + ly[v] - g[u][v];
if(slack[v] >= cur) {
pre[v] = u;
if(cur) slack[v] = cur;
else if(Path(v)) return;
}
}
}
LL a = INF;
rep(i, 1, n) if(! vy[i]) a = min(a, slack[i]);
rep(i, 1, n) if(vx[i]) lx[i] -= a;
rep(i, 1, n) if(vy[i]) ly[i] += a; else slack[i] -= a;
rep(i, 1, n) if(! vy[i] && ! slack[i] && Path(i))
return;
}
}

void KM() {
rep(i, 1, n) rep(j, 1, n) lx[i] = max(lx[i], g[i][j]);
rep(i, 1, n) {rep(j, 1, n) vx[j] = vy[j] = false, slack[j]
= INF; Bfs(i);}
}

int main() {
n = read(), m = read();
rep(i, 1, n) rep(j, 1, n) g[i][j] = - INF;
rep(i, 1, m) {
int u = read(), v = read();
LL w = read() + M; g[u][v] = max(g[u][v], w);
}
KM();
LL ans = 0;
rep(i, 1, n) ans += g[i][mx[i]];
printf("%lld\n", ans - 1LL * n * M);
rep(i, 1, n) printf("%d ", my[i]); puts("");
return 0;
}

【4】字符串相关

SA

void Get_Sa(){
for(int i = 1; i <= 256; i ++) bac[i] = 0;
for(int i = 1; i <= n; i ++) bac[str[i]] ++;
for(int i = 1; i <= 256; i ++) bac[i] += bac[i - 1];
for(int i = 1; i <= n; i ++) sa[bac[str[i]] --] = i;
for(int i = 1; i <= n; i ++) rk[sa[i]] = rk[sa[i - 1]] +
(str[sa[i]] != str[sa[i - 1]]);

for(int p = 1; p <= n; p <<= 1){


for(int i = 1; i <= n; i ++) bac[rk[sa[i]]] = i;
for(int i = n; i >= 1; i --) if(sa[i] > p)
SA[bac[rk[sa[i] - p]] --] = sa[i] - p;
for(int i = n; i > n - p; i --) SA[bac[rk[i]] --] = i;
#define comp(x, y) (rk[x] != rk[y] || rk[x + p] !=
rk[y + p])
for(int i = 1; i <= n; i ++) RK[SA[i]] = RK[SA[i - 1]]
+ comp(SA[i], SA[i - 1]);
for(int i = 1; i <= n; i ++) rk[i] = RK[i], sa[i] =
SA[i];
if(rk[sa[n]] == n) break;
}
}
// 这里用 lcp 代替 height
void Get_H(){
for(int i = 1; i <= n; i ++){
int j = sa[rk[i] - 1], k = max(lcp[rk[i - 1]] - 1, 0);
while(str[i + k] == str[j + k] && str[i + k]) k ++;
lcp[rk[i]] = k;
}
}

AC自动机

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 2000010;

int n, ans, tot;


int tr[N][30], fail[N], pos[N];
int dep[N], arc[N], bac[N], cov[N];
char str[N];

int insert(char *str){


int len = strlen(str + 1), p = 0;
for(int i = 1; i <= len; i ++){
int ch = str[i] - 'a';
if(!tr[p][ch]) tr[p][ch] = ++ tot;
p = tr[p][ch];
dep[p] = i;
}
return p;
}

void build(){
for(int i = 1; i <= tot; i ++) bac[dep[i]] ++;
for(int i = 1; i <= tot; i ++) bac[i] += bac[i - 1];
for(int i = 1; i <= tot; i ++) arc[bac[dep[i]] --] = i;

for(int i = 1; i <= tot; i ++){


int u = arc[i];
for(int v = 0; v < 26; v ++)
if(tr[u][v]) fail[tr[u][v]] = tr[fail[u]][v];
else tr[u][v] = tr[fail[u]][v];
}
}

void query(char *str){


int len = strlen(str + 1), p = 0;
for(int i = 1; i <= len; i ++){
p = tr[p][str[i] - 'a'];
cov[p] ++;
}
}

void dp(){
for(int i = tot; i >= 1; i--){
int u = arc[i];
cov[fail[u]] += cov[u];
}
}

int main(){
scanf("%d", &n);
for(int i = 1; i <= n; i ++)
scanf("%s", str + 1), pos[i] = insert(str);
build();
scanf("%s", str + 1);
query(str);
dp();
int ans = 0;
for(int i = 1; i <= n; i ++)
printf("%d\n", cov[pos[i]]);
return 0;
}

最小表示法

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#define N 1000010
using namespace std;

int n,a[N];

int read(){
int x=0,f=1;char c=getchar();
while(c<'0' || c>'9') f=(c=='-')?-1:1,c=getchar();
while(c>='0' && c<='9') x=x*10+c-48,c=getchar();
return x*f;
}

int main(){
n=read();
for(int i=1;i<=n;i++) a[i]=read(),a[i+n]=a[i];
int i=1,j=2,k;
while(i<=n && j<=n){
for(k=0;k<n && a[i+k]==a[j+k];k++)
if(k==n) break;
if(a[i+k]>a[j+k]){
i=i+k+1;
if(i==j) i++;
}
else{
j=j+k+1;
if(i==j) j++;
}
}
int ans=min(i,j);
for(int i=ans;i<=ans+n-1;i++) printf("%d ",a[i]);
return 0;
}

PAM

#include<bits/stdc++.h>
typedef long long LL;
#define rep(i, s, t) for(int i = (s); i <= (t); i ++)
#define per(i, s, t) for(int i = (s); i >= (t); i --)
#define Ede(i, u) for(int i = head[u]; i; i = e[i].nxt)
using namespace std;

int read() {
int x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') f = (c == '-') ? -1 : 1, c =
getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - 48, c =
getchar();
return x * f;
}

const int N = 5e5 + 10;


int n, tot, las, len[N], num[N], fail[N], tr[N][30];
char s[N], str[N];

int New(int l) {len[++ tot] = l; return tot;}


void Bui() {tot = - 1, fail[n = las = New(0)] = New(- 1);}

int Get(int x) {
while(s[n - len[x] - 1] != s[n]) x = fail[x];
return x;
}
int Ins(char c) {
s[++ n] = c;
int cur = Get(las);
if(! tr[cur][c - 'a']) {
int now = New(len[cur] + 2);
fail[now] = tr[Get(fail[cur])][c - 'a'];
num[tr[cur][c - 'a'] = now] = num[fail[now]] + 1;
}
return num[las = tr[cur][c - 'a']];
}

int main() {
Bui();
scanf("%s", str + 1);
int n = strlen(str + 1), k;
rep(i, 1, n) {
char c = (i > 1) ? (str[i] - 97 + k) % 26 + 97 :
str[1];
printf("%d ", k = Ins(c));
} puts("");
return 0;
}

SAM

#include<bits/stdc++.h>
typedef long long LL;
#define rep(i, s, t) for(int i = (s); i <= (t); i ++)
#define per(i, s, t) for(int i = (s); i >= (t); i --)
#define Ede(i, u) for(int i = head[u]; i; i = e[i].nxt)
using namespace std;

const int N = 2e6 + 10;


int n;
char str[N];

int tot = 1, las = 1;


int len[N], fail[N], siz[N], tr[N][30];
void Ins(int c) {
int cur = ++ tot, anc = las;
len[cur] = len[las] + 1;
siz[cur] = 1;
while(anc && ! tr[anc][c]) tr[anc][c] = cur, anc =
fail[anc];
if(! anc) fail[cur] = 1;
else {
int now = tr[anc][c];
if(len[now] == len[anc] + 1) fail[cur] = now;
else {
int clo = ++ tot;
len[clo] = len[anc] + 1;
fail[clo] = fail[now];
memcpy(tr[clo], tr[now], sizeof(tr[now]));
fail[now] = fail[cur] = clo;
while(anc && tr[anc][c] == now) tr[anc][c] = clo,
anc = fail[anc];
}
}
las = cur;
}

int bac[N], arc[N];

int main() {
scanf("%s", str + 1), n = strlen(str + 1);
rep(i, 1, n) Ins(str[i] - 'a');
rep(i, 1, tot) bac[len[i]] ++;
rep(i, 1, tot) bac[i] += bac[i - 1];
rep(i, 1, tot) arc[bac[len[i]] --] = i;
LL ans = 0;
per(i, tot, 1) {
int o = arc[i];
if(siz[o] > 1) ans = max(ans, 1LL * siz[o] * len[o]);
siz[fail[o]] += siz[o];
}
printf("%lld\n", ans);
return 0;
}
【5】数据结构相关

平衡树与 LCT
Fhq-Treap

#include<bits/stdc++.h>
typedef long long LL;
typedef unsigned long long ULL;
#define rep(i, a, b) for(int i = (a); i <= (b); i ++)
#define per(i, a, b) for(int i = (a); i >= (b); i --)
using namespace std;

inline int read() {


int x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') f = (c == '-') ? -1 : 1, c =
getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - 48, c =
getchar();
return x * f;
}

const int N = 1e5 + 10;


int n, m, tot, root;
struct node {int l, r, siz, rnd, tag;} t[N];

mt19937 myrand(19260817);

int init() {
t[++ tot] = (node) {0, 0, 1, (int)(myrand() >> 1), 0};
return tot;
}

void pushup(int x) {
t[x].siz = t[t[x].l].siz + t[t[x].r].siz + 1;
}

void pushdw(int x) {
if(t[x].tag)
swap(t[x].l, t[x].r),
t[t[x].l].tag ^= 1,
t[t[x].r].tag ^= 1,
t[x].tag = 0;
}

int merge(int x, int y) {


if(!x || !y) return x | y;
if(t[x].rnd < t[y].rnd)
return pushdw(x), t[x].r = merge(t[x].r, y),
pushup(x), x;
else
return pushdw(y), t[y].l = merge(x, t[y].l),
pushup(y), y;
}

void split(int o, int k, int &x, int &y) {


if(!o) return x = y = 0, void();
pushdw(o);
if(t[t[o].l].siz + 1 <= k)
x = o, split(t[o].r, k - t[t[o].l].siz - 1, t[x].r,
y), pushup(x);
else
y = o, split(t[o].l, k, x, t[y].l), pushup(y);
}

void print(int o) {
pushdw(o);
if(t[o].l) print(t[o].l);
printf("%d ", o);
if(t[o].r) print(t[o].r);
}

int main() {
n = read(), m = read();
rep(i, 1, n) root = merge(root, init());
rep(i, 1, m) {
int l = read(), r = read();
int x, y;
split(root, l - 1, root, x);
split(x, r - l + 1, x, y);
t[x].tag ^= 1;
root = merge(root, merge(x, y));
}
print(root); puts("");
return 0;
}

LCT

#include<bits/stdc++.h>
#define MP make_pair
#define rep(i, s, t) for(int i = (s); i <= (t); i ++)
using namespace std;

const int N = 4e5 + 10;


int n, m, U[N], V[N], W[N];
bool vis[N];
priority_queue<pair<int, int> > q;

int read() {
int x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') f = (c == '-') ? - 1 : 1, c =
getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - 48, c =
getchar();
return x * f;
}

struct LCT {
int cnt, fa[N], c[N][2], siz[N], si[N], inv[N], mxp[N],
val[N], stk[N];
#define L(o) c[o][0]
#define R(o) c[o][1]
#define Con(x, y, o) fa[c[y][o] = x] = y;
#define Root(o) (c[fa[o]][0] != o && c[fa[o]][1] != o)
void Upd(int o) {
siz[o] = siz[L(o)] + siz[R(o)] + si[o] + (o <= n);
mxp[o] = val[mxp[L(o)]] > val[mxp[R(o)]] ? mxp[L(o)] :
mxp[R(o)];
mxp[o] = val[o] > val[mxp[o]] ? o : mxp[o];
}
void Dow(int o) {
if(inv[o]) {
inv[L(o)] ^= 1, inv[R(o)] ^= 1;
swap(L(o), R(o)), inv[o] = 0;
}
}

void Rot(int X) {
int Y = fa[X], Yson = (X == R(Y));
int R = fa[Y], Rson = (Y == R(R));
int B = c[X][Yson ^ 1];
if(! Root(Y)) c[R][Rson] = X; fa[X] = R;
Con(Y, X, Yson ^ 1); Con(B, Y, Yson);
Upd(Y), Upd(X);
}

void Splay(int o) {
int tot = 0; stk[++ tot] = o;
for(int i = o; fa[i]; i = fa[i]) stk[++ tot] = fa[i];
for(int i = tot; i; i --) Dow(stk[i]);
while(! Root(o)) {
int x = fa[o], y = fa[x];
if(Root(x)) Rot(o);
else if((o == R(x)) == (x == R(y)))
Rot(x), Rot(o);
else
Rot(o), Rot(o);
}
}

void Access(int x) {
for(int y = 0; x; y = x, x = fa[x]) {
Splay(x);
si[x] += siz[R(x)];
si[x] -= siz[R(x) = y];
Upd(x);
}
}
void Make(int o) {Access(o), Splay(o), inv[o] ^= 1;}

void Split(int x, int y) {Make(x), Access(y), Splay(y);}

int Find(int o) {
Access(o), Splay(o), Dow(o);
while(L(o)) o = L(o), Dow(o);
Splay(o); return o;
}

void Link(int x, int y) {


Split(x, y), cnt -= siz[x] & 1, cnt -= siz[y] & 1;
si[fa[x] = y] += siz[x], Upd(y), cnt += siz[y] & 1;
}

void Cut(int x, int y) {


Split(x, y), cnt -= siz[y] & 1;
fa[x] = L(y) = 0, Upd(y), cnt += siz[x] & 1, cnt +=
siz[y] & 1;
}

int Ins(int i) {
int x = U[i], y = V[i], z = W[i];
bool flag = true;
if(Find(x) == Find(y)) {
Split(x, y);
int o = mxp[y];
if(val[o] > z) Cut(U[o - n], o), Cut(V[o - n], o),
vis[o - n] = true;
else flag = false;
}
if(flag) {
val[i + n] = z, mxp[i + n] = i + n;
Link(x, i + n), Link(y, i + n), q.push(MP(z, i));
}
if(cnt) return - 1;
while(! q.empty()) {
int o = q.top().second; q.pop();
if(vis[o]) continue;
Cut(U[o], o + n), Cut(V[o], o + n);
if(cnt) {
Link(U[o], o + n), Link(V[o], o + n);
q.push(MP(W[o], o)); return W[o];
}
}
return 0;
}
} T;

int main() {
n = read(), m = read();
T.cnt = n;
rep(i, 1, n) T.siz[i] = 1, T.mxp[i] = i;
rep(i, 1, m)
U[i] = read(), V[i] = read(), W[i] = read(),
printf("%d\n", T.Ins(i));
return 0;
}

点分树

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;

const int N = 100010;


int n, m, rt, cnt;
int a[N], sz[N], fa[N], mxp[N];
int head[N], dep[N], st[N][30];
bool vis[N];
struct Edge{int nxt, to;} ed[N * 2];
vector<int> C[2][N];

int read(){
int x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') f = (c == '-') ? -1 : 1, c =
getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - 48, c =
getchar();
return x * f;
}

void add(int u, int v){


ed[++ cnt] = (Edge){head[u], v};
head[u] = cnt;
}

void dfs1(int u, int Fa){


dep[u] = dep[Fa] + 1; st[u][0] = Fa;
for(int i = 1; (1 << i) <= dep[u]; i ++)
st[u][i] = st[st[u][i - 1]][i - 1];
for(int i = head[u], v; i; i = ed[i].nxt)
if((v = ed[i].to) != Fa) dfs1(v, u);
}

int Get_Lca(int x, int y){


if(dep[x] > dep[y]) swap(x, y);
for(int i = 20; i >= 0; i --)
if(dep[st[y][i]] >= dep[x]) y = st[y][i];
if(x == y) return x;
for(int i = 20; i >= 0; i --)
if(st[x][i] != st[y][i])
x = st[x][i], y = st[y][i];
return st[x][0];
}

int Get_Dis(int x, int y){


int z = Get_Lca(x, y);
return dep[x] + dep[y] - 2 * dep[z];
}

void Get_Size(int u, int Fa){


sz[u] = 1;
for(int i = head[u], v; i; i = ed[i].nxt)
if(!vis[v = ed[i].to] && v != Fa)
Get_Size(v, u), sz[u] += sz[v];
}

void Get_Root(int u, int Fa, int top){


mxp[u] = sz[top] - sz[u];
for(int i = head[u], v; i; i = ed[i].nxt)
if(!vis[v = ed[i].to] && v != Fa)
Get_Root(v, u, top), mxp[u] = max(mxp[u], sz[v]);
if(!rt || mxp[u] < mxp[rt]) rt = u;
}

void dfs2(int u, int Fa){


Get_Size(u, 0); rt = 0; Get_Root(u, 0, u);
u = rt; fa[u] = Fa; vis[u] = true;
Get_Size(u, 0); sz[u] ++;
C[0][u].resize(sz[u] + 2);
C[1][u].resize(sz[u] + 2);
for(int i = head[u], v; i; i = ed[i].nxt)
if(!vis[v = ed[i].to]) dfs2(v, u);
}

void Change(int u, int t, int x, int v){


x ++;
for(; x <= sz[u]; x += x & -x) C[t][u][x] += v;
}

int Ask(int u, int t, int x){


x ++; int sum = 0;
x = min(x, sz[u]);
for(; x; x -= x & -x) sum += C[t][u][x];
return sum;
}

void Modify(int u, int v){


Change(u, 0, 0, v);
for(int i = u; fa[i]; i = fa[i]){
int dis = Get_Dis(fa[i], u);
Change(fa[i], 0, dis, v);
Change(i, 1, dis, v);
}
}

int Query(int u, int k){


int sum = Ask(u, 0, k);
for(int i = u; fa[i]; i = fa[i]){
int dis = Get_Dis(u, fa[i]);
if(dis > k) continue;
sum += Ask(fa[i], 0, k - dis);
sum -= Ask(i, 1, k - dis);
}
return sum;
}

int main(){
n = read(), m = read();
for(int i = 1; i <= n; i ++) a[i] = read();
for(int i = 1; i < n; i ++){
int u = read(), v = read();
add(u, v), add(v, u);
}
dfs1(1, 0);
dfs2(1, 0);
for(int i = 1; i <= n; i ++) Modify(i, a[i]);
int ans = 0;
while(m --){
int opt = read(), x = read(), y = read();
x ^= ans, y ^= ans;
if(!opt) printf("%d\n", ans = Query(x, y));
else Modify(x, y - a[x]), a[x] = y;
}
return 0;
}

左偏树

#include<bits/stdc++.h>
typedef long long LL;
#define rep(i, s, t) for(int i = (s); i <= (t); i ++)
#define per(i, s, t) for(int i = (s); i >= (t); i --)
#define Ede(i, u) for(int i = head[u]; i; i = e[i].nxt)
using namespace std;

int read() {
int x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') f = (c == '-') ? -1 : 1, c =
getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - 48, c =
getchar();
return x * f;
}

const int N = 5e5 + 10;


int n, tot, las, len[N], num[N], fail[N], tr[N][30];
char s[N], str[N];

int New(int l) {len[++ tot] = l; return tot;}


void Bui() {tot = - 1, fail[n = las = New(0)] = New(- 1);}

int Get(int x) {
while(s[n - len[x] - 1] != s[n]) x = fail[x];
return x;
}

int Ins(char c) {
s[++ n] = c;
int cur = Get(las);
if(! tr[cur][c - 'a']) {
int now = New(len[cur] + 2);
fail[now] = tr[Get(fail[cur])][c - 'a'];
num[tr[cur][c - 'a'] = now] = num[fail[now]] + 1;
}
return num[las = tr[cur][c - 'a']];
}

int main() {
Bui();
scanf("%s", str + 1);
int n = strlen(str + 1), k;
rep(i, 1, n) {
char c = (i > 1) ? (str[i] - 97 + k) % 26 + 97 :
str[1];
printf("%d ", k = Ins(c));
} puts("");
return 0;
}

You might also like