XCPC板子
XCPC板子
【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 的所有原根?
于是我们可以在 O(n0.25logn)。
#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 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;
}
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;
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];
}
}
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。
这些数应该是最小质因子恰好为 的合数。
我们可以提出来一个 作为最小质因子,这样剩下的就不能有小于它的质因
子了,也就是 ,后面那个g是为了把所有的质数去
掉。
这样我们就得到了g的递推式:
完全积性函数的好处在这里就体现出来了:由于只提出了一个 ,所以后面
还有可能有 这个因子,如果是完全积性函数的话就可以将函数值直接相
乘,而不用管是否互质。
但是因为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;
int n, a[21][1 << 20], b[21][1 << 20], f[21][1 << 20];
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();
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;
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;
}
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;
}
二次剩余
#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;
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 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);
}
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;
}
#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;
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 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 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;
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;
}
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;
}
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;
}
int dfn[N],col[N],low[N],s[N],tot=0,color=0,tim=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;
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
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;}
}
Dinic 与 费用流
Dinic
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
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 Max_Flow(){
int Flow = 0, flow;
while(bfs())
while(flow = Dinic(S, INF)) Flow += flow;
return Flow;
}
最小费用最大流:
#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
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);}
}
}
}
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;
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;
}
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 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;
割点
#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
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;
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;
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(), 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
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;
}
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;
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;
}
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]]);
AC自动机
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 2000010;
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;
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;
}
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;
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;
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;
}
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;
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;}
int Find(int o) {
Access(o), Splay(o), Dow(o);
while(L(o)) o = L(o), Dow(o);
Splay(o); return o;
}
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;
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();
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;
}
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;
}