省选模板复习计划

快读

inline long long read(){
	long long x=0,f=1;char ch=getchar();
	while ((ch!='-')&&(!isdigit(ch))) ch=getchar();
	if (ch=='-') f=-1,ch=getchar();
	while (isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
	return x*f;
}

数学

组合数学

第二类斯特林数

{nm}={n1m1}+m×{n1m}{n0}=[n=0]{nm}=i=0m(1)mi×ini!×(mi)!ki=j=0i{ij}×kj_

与点值表达之间的关系:

f(x)=i=0nbi×xi_ak=i=0nbi×ki_akk!=i=0kbi×1(ki)!

第一类斯特林数

[nk]=[n1k1]+(n1)×[n1k][n0]=[n=0]

康托展开

long long i,E[1001010],n,MOD,a[1001010],fac[1001010],ans;
long long query(long long x){
	long long ans=0;
	for (;x;x-=x&-x) ans=ans+E[x];return ans;
}
void modify(long long x,long long  y){
	for (;x<=n;x+=x&-x) E[x]=E[x]+y;
}
int main()
{
	n=read();MOD=998244353;
	for (i=1;i<=n;i++) a[i]=read();
	fac[0]=1;for (i=1;i<=n;i++) fac[i]=fac[i-1]*i % MOD;
	for (i=n;i>=1;i--){
		ans=(ans+fac[n-i]*query(a[i])) % MOD;
		modify(a[i],1);
	}
	printf("%lld\n",(ans+1) % MOD);
return 0;
}

卢卡斯定理

(nm)=(nPmP)×(n%Pm%P)

高斯消元

	n=read();eps=1e-9;
	for (i=1;i<=n;i++)
		for (j=1;j<=n+1;j++) a[i][j]=read();
	for (now=1;now<n;now++){mx=0;id=0;
		for (nxt=now;nxt<=n;nxt++) if (fabs(a[nxt][now])>mx) mx=fabs(a[nxt][now]),id=nxt;
		if (mx<=eps){puts("No Solution");return 0;}swap(a[now],a[id]);
		for (nxt=now+1;nxt<=n;nxt++) 
			 for (i=n+1;i>=now;i--) a[nxt][i]=a[nxt][i]-(a[now][i]*(a[nxt][now]/a[now][now]));
		//a[nxt][now]-a[now][now]*(a[nxt][now]*a[now][now])
	}
	if (fabs(a[n][n])<=eps) {puts("No Solution");return 0;}
	for (i=n;i>=1;i--){
		sum=a[i][n+1];
		for (j=i+1;j<=n;j++) sum=sum-X[j]*a[i][j];
		X[i]=sum/a[i][i]; 
	}
	for (i=1;i<=n;i++) printf("%.2lf\n",X[i]);

行列式

求值

	n=read();MOD=read();
	for (i=1;i<=n;i++)
	   for (j=1;j<=n;j++)
	       a[i][j]=read();
    for (now=1;now<n;now++)
        for (i=now+1;i<=n;i++){
        	sym=1;//目的a[i][now] 都变为0 
        	while (a[now][now]!=0){
        	    G=a[i][now]/a[now][now];
        	    for (j=now;j<=n;j++) a[i][j]=(a[i][j]-G*a[now][j] % MOD+MOD) % MOD;
        	    for (j=now;j<=n;j++) swap(a[now][j],a[i][j]);sym=MOD-sym;
			}
			//a[now][now]=0 交换i,now两行
			for (j=now;j<=n;j++) swap(a[now][j],a[i][j]);sym=MOD-sym;
			for (j=now;j<=n;j++) a[i][j]=a[i][j]*sym % MOD; 
		}
   ans=1;
   for (i=1;i<=n;i++) ans=ans*a[i][i] % MOD;
   printf("%lld\n",ans); 

LGV引理

看自己的学习笔记

矩阵树定理

看自己的学习笔记

莫比乌斯反演相关

F(n)=n|df(d)f(n)=n|dμ(dn)×F(d)μId=φ()

Ask:i=1nf(i)S(n)=i=1nf(i)h=fgi=1nh(i)=i=1nd|if(id)×g(d)=d=1ng(d)j=1ndf(j)=d=1ng(d)×S(nd)g(1)×S(n)=i=1nh(i)i=2ng(d)×S(nd)

要求 hg 的前缀和好求出

μI=ϵφI=Idf(i)=i×φ(i)h(i)=i2fId=h

BSGS

	P=read();x=read();n=read();B=sqrt(P-1);G=1;
	for (i=1;i<B;i++) {
		G=G*x % P;
		if (mp[G]==0) mp[G]=i; 
	}
	G=G*x % P;invG=pow(G,P-2,P);now=1;tag=1;
	for (i=0;i*B<=P-1;i++){
         if (now==n) {
         	printf("%lld\n",i*B);return 0;
		 }
		 if (mp[n*tag % P]) {
		 	printf("%lld\n",i*B+mp[n*tag % P]);return 0;
		 }tag=tag*invG % P;
		 now=now*G % P;
	} puts("no solution");

Exgcd

void exgcd(long long A,long long B){
	if (B==0){x=1;y=0;return ;}
	exgcd(B,A % B);
	long long z=x;x=y;y=z-(A/B)*y;
} 
void Main(){
	A=read();B=read();C=read();
	if (C % __gcd(A,B)!=0) {puts("-1");return ;}
	down=B/__gcd(A,B);up=A/__gcd(A,B);
	exgcd(A,B);x=x*(C/__gcd(A,B));y=y*(C/__gcd(A,B));
	if (x<=0) {V=(-x)/down+1;x=x+V*down;y=y-V*up;}
	if (x>0){V=(x-1)/down;x=x-V*down;y=y+V*up;}
	if ((y<=0)){printf("%lld ",x);V=(-y)/up+1;y=y+V*up;printf("%lld\n",y);return ;}
    V=(y-1)/up;printf("%lld %lld %lld %lld %lld\n",V+1,x,y-V*up,x+V*down,y);
}

Excrt

n=read();
	for (i=1;i<=n;i++) a[i]=read(),b[i]=read(),b[i]%=a[i];
	if (n==1) {ans=b[1];printf("%lld\n",ans);return 0;}
	for (i=2;i<=n;i++){
		if (b[i-1]>b[i]) swap(a[i],a[i-1]),swap(b[i],b[i-1]);
		exgcd(a[i-1],a[i]);B=-B;V=a[i]/__gcd(a[i],a[i-1])*a[i-1];
		A=A*((b[i]-b[i-1])/__gcd(a[i],a[i-1]));B=B*((b[i]-b[i-1])/__gcd(a[i],a[i-1]));
		Vb=a[i-1]/__gcd(a[i],a[i-1]);
		if (B>=0) B=B % Vb;else B=B+((-B-1)/Vb+1)*Vb;
		if (i==n) {ans=a[i]*B+b[i];printf("%lld\n",ans);return 0;}
		b[i]=a[i]*B+b[i];a[i]=V;b[i]%=a[i];
		}

裴蜀定理

n=read();
	for (i=1;i<=n;i++) x=read(),ans=__gcd(ans,abs(x));
	printf("%lld\n",ans);

Polya 定理

我们考虑定义 F(x) 表示循环节至少为 x 的方案数

f(x) 表示循环节恰好为 x 的方案数

F(x)=d|xf(d)=nxf(x)=d|xμ(d)×F(xd)

而一个环从任意一个起点开始,遍历下来都是同一个环,所以我们可以得到答案为:

d|nf(d)d=1nd|nf(d)×nd=1nd|nndj|ndμ(j)×(ndj)=1nd|nnd×φ(nd)

Dirichlet前缀和

	n=read();seed=read();
	for (i=1;i<=n;i++) a[i]=getnext();
	for (i=2;i<=n;i++){
		if (vis[i]==false) prim[++len]=i;
		for (j=1;j<=len&&i*prim[j]<=n;j++){
			vis[i*prim[j]]=true;if (i % prim[j]==0) break;
		}
	}
	for (i=1;i<=len;i++)
	   for (j=1;j*prim[i]<=n;j++)
	        a[prim[i]*j]+=a[j];
	for (i=1;i<=n;i++) ans^=a[i];
	printf("%u\n",ans);

扩展欧拉定理

bφ(m)abab mod φ(m)+φ(m)(mod m)

数据结构

线性基

void insert(long long x){
	for (int i=63;i>=0;i--)
	    if (x&(1ll<<i)){
	    	if (f[i]==0){f[i]=x;return ;}
	    	x^=f[i];
		}
}
int main()
{
	n=read();
	for (i=1;i<=n;i++) insert(read());
	for (i=63;i>=0;i--) ans=max(ans,ans^f[i]);
	printf("%lld\n",ans);
return 0;
}

线段树

板子

线段树合并

void add(int x,int y){
	cnt++;a[cnt]=y;b[cnt]=d[x];d[x]=cnt;
}
void sc(int x,int fa){
	Fa[x][0]=fa;
	for (int i=1;i<=20;i++) Fa[x][i]=Fa[Fa[x][i-1]][i-1];
	for (int i=d[x];i;i=b[i])
	     if (a[i]!=fa)
	       dep[a[i]]=dep[x]+1,sc(a[i],x);
}
int lca(int x,int y){
	if (dep[x]<dep[y]) swap(x,y);
	for (int i=20;i>=0;i--)
	    if (dep[Fa[x][i]]>=dep[y]) x=Fa[x][i];
	if (x==y) return x;
	for (int i=20;i>=0;i--)
	     if (Fa[x][i]!=Fa[y][i]) x=Fa[x][i],y=Fa[y][i];
	return Fa[x][0];
}
void update(int x){
	tree[x].val=max(tree[tree[x].lft].val,tree[tree[x].rit].val);
	if (tree[x].val==tree[tree[x].lft].val) tree[x].pos=tree[tree[x].lft].pos;
	else tree[x].pos=tree[tree[x].rit].pos;
}
void merge(int sx,int tx,int l,int r){
	if (l==r){
		tree[sx].val=tree[sx].val+tree[tx].val;
		tree[sx].pos=l;
		return ;
	}
	int mid=(l+r)>>1;
	if ((tree[sx].lft>0)&&(tree[tx].lft>0)) merge(tree[sx].lft,tree[tx].lft,l,mid);
	else if (tree[tx].lft>0) tree[sx].lft=tree[tx].lft;
	if ((tree[sx].rit>0)&&(tree[tx].rit>0)) merge(tree[sx].rit,tree[tx].rit,mid+1,r);
	else if (tree[tx].rit>0) tree[sx].rit=tree[tx].rit;
	update(sx);
}
void modify(int x,int l,int r,int pos,int val){
	if (l==r){
		tree[x].val+=val;
		tree[x].pos=l;
		return ;
	}
	int mid=(l+r)>>1;
	if (pos<=mid){
		if (tree[x].lft==0) tree[x].lft=++id;
		modify(tree[x].lft,l,mid,pos,val);
	}
	else {
		if (tree[x].rit==0) tree[x].rit=++id;
		modify(tree[x].rit,mid+1,r,pos,val);
	}
	update(x);
}
void solve(int x,int fa){
	if (rt[x]==0) rt[x]=++id;
	for (int i=d[x];i;i=b[i])
	     if (a[i]!=fa){
	     	solve(a[i],x);
	     	merge(rt[x],rt[a[i]],1,100000);
		 }
	for (int i=0;i<chg[x].size();i++){
		int pos=chg[x][i].first;
		int val=chg[x][i].second;
		modify(rt[x],1,100000,pos,val);
	}
	if (tree[rt[x]].val==0) Answer[x]=0;
	else Answer[x]=tree[rt[x]].pos;
}
int main()
{
	n=read();M=read();
	for (i=1;i<n;i++){
		x=read();y=read();
		add(x,y);add(y,x);
	}
	dep[1]=1;
	sc(1,0);
	for (;M;M--){
		x=read();y=read();val=read();
		z=lca(x,y);	
		chg[x].push_back(make_pair(val,1));
		chg[y].push_back(make_pair(val,1));
		chg[z].push_back(make_pair(val,-1));
		chg[Fa[z][0]].push_back(make_pair(val,-1));
		}
	solve(1,0);
	for (i=1;i<=n;i++) printf("%lld\n",Answer[i]);
	return 0;
}

优化建图

void add(int x,int y,int z){
	cnt++;a[cnt]=y;b[cnt]=d[x];c[cnt]=z;d[x]=cnt;
}
void buildup(int x,int l,int r){
	treeup[x].id=++id;
	if (l==r) {
		posup[l]=treeup[x].id;
		return ;
	}
	int mid=(l+r)>>1;
	buildup(x<<1,l,mid);
	buildup(x<<1|1,mid+1,r);
	add(treeup[x<<1].id,treeup[x].id,0);
	add(treeup[x<<1|1].id,treeup[x].id,0);
	return ;
}
void builddown(int x,int l,int r){
	treedown[x].id=++id;
	if (l==r) {
		posdown[l]=treedown[x].id;
		return ;
	}
	int mid=(l+r)>>1;
	builddown(x<<1,l,mid);
	builddown(x<<1|1,mid+1,r);
	add(treedown[x].id,treedown[x<<1].id,0);
	add(treedown[x].id,treedown[x<<1|1].id,0);
	return ;
}
void build(int x,int l,int r,int tl,int tr,int cas){
	if ((l>=tl)&&(r<=tr)){
		if (cas==0) add(posup[v],treedown[x].id,val);
		if (cas==1) add(treeup[x].id,posdown[u],val);
		return ;
	}
	int mid=(l+r)>>1;
	if (tl<=mid) build(x<<1,l,mid,tl,tr,cas);
	if (tr>mid) build(x<<1|1,mid+1,r,tl,tr,cas);
	return ;
}
int main()
{
	n=read();Q=read();st=read();
	buildup(1,1,n);
	builddown(1,1,n);
	for (;Q;Q--){
		opt=read();
		if (opt==1) v=read(),l=read(),r=l;
		if (opt==2) v=read(),l=read(),r=read();
		if (opt==3) u=read(),l=read(),r=read();
		val=read();
		if (opt<=2) build(1,1,n,l,r,0);
		else build(1,1,n,l,r,1);
	}
	for (i=1;i<=n;i++) add(posup[i],posdown[i],0),add(posdown[i],posup[i],0);
	for (i=1;i<=id;i++) dis[i]=1e18;
	dis[posup[st]]=0;
	q.push(make_pair(0,posup[st]));
	while (!q.empty()){
		now=q.top().second;q.pop();
		if (vis[now]) continue;
		vis[now]=true;
		for (int i=d[now];i;i=b[i])
		    if (dis[a[i]]>dis[now]+c[i]){
		    	dis[a[i]]=dis[now]+c[i];
		    	q.push(make_pair(dis[a[i]],a[i]));
			}
	}
	for (i=1;i<=n;i++)
	    if (dis[posup[i]]==1e18) dis[posup[i]]=-1;
	for (i=1;i<=n;i++) printf("%lld ",dis[posup[i]]);
return 0;
}

树状数组

板子

树状数组上二分

Splay Tree

普通平衡树

int val[1001010],id,rt,fre[1001010],fa[1001010],son[1001001][2],siz[2001010],Testing,opt,x;
void change(int x,int Fa,int dir){id++;val[id]=x;fre[id]=siz[id]=1;fa[id]=Fa;son[Fa][dir]=id;}
void Clear(int x){
	val[x]=siz[x]=fre[x]=fa[x]=son[x][0]=son[x][1]=0;
}
void modify(int x){
	siz[x]=siz[son[x][1]]*(son[x][1]>0)+siz[son[x][0]]*(son[x][0]>0)+fre[x];
}
int Gdir(int x){return (son[fa[x]][1]==x);}
void rotate(int x){
	if (fa[x]==0) return ;
	int F1,F2,D1,D2;F1=fa[x];F2=fa[F1];D1=Gdir(x);
	if (F2!=0) son[F2][Gdir(F1)]=x;
	fa[x]=F2;fa[F1]=x;son[F1][D1]=son[x][D1^1];
	if (son[x][D1^1]) fa[son[x][D1^1]]=F1;son[x][D1^1]=F1;
	modify(F1);modify(x);
}
void splay(int x){
	while (fa[x]){
		if ((fa[fa[x]])&&(Gdir(fa[x])==Gdir(x))) rotate(fa[x]);else rotate(x);
		rotate(x);}
	rt=x;
}
int findval(int x){
	int now=rt;
	while (1){
		if (siz[son[now][0]]>=x) now=son[now][0];
		else {
			x-=siz[son[now][0]];
			if (x<=fre[now]){splay(now);return now;}
			x-=fre[now];now=son[now][1];
		}
	}
}
int findrank(int x){
	int tot=0,now=rt;
	while (now){
		if (val[now]>x) now=son[now][0];
		else {
			tot+=siz[son[now][0]];
			if (val[now]==x) break;
			tot+=fre[now];now=son[now][1];
		}
	}if (now!=0) splay(now);return tot;
}
int findpre(int x){int G=findrank(x);if (G==0) return 0;return findval(G);}
int findsuf(int x){
	int G=findrank(x);
	if (G==siz[rt]) return 0;
	findval(G+1);
	if (val[rt]!=x) return rt;
	int now=son[rt][1];
	while (son[now][0]) now=son[now][0];return now;
}
void Insert(int x){
	if (rt==0){id++;val[id]=x;siz[id]=fre[id]=1;rt=id;return ;}
	int G=findrank(x);
	if (G==0){
		findval(1);
		if (x==val[rt]) {fre[rt]++;siz[rt]++;return ;}
		change(x,rt,0);splay(id);return ;}findval(G);
    if (son[rt][1]==0){change(x,rt,1);splay(id);return ;}
    int now=son[rt][1];
    while (son[now][0]) now=son[now][0];
    if (x==val[now]) {fre[now]++;siz[now]++;splay(now);return ;}change(x,now,0);splay(id);return ;
}
void Delete(int x){
	if (siz[rt]==0){Clear(rt);rt=0;return ;}
	int G=findrank(x);
	if (G==0){findval(1);
	    if (fre[rt]>1){fre[rt]--;siz[rt]--;return ;}int nxt=son[rt][1];fa[nxt]=0;
		Clear(rt);rt=nxt;return ;	
	}findval(G);
	int now=son[rt][1];
	while (son[now][0]) now=son[now][0];
	if (fre[now]>1){fre[now]--;siz[now]--;splay(now);return ;}
	son[fa[now]][Gdir(now)]=son[now][1];
	if (son[now][1]) fa[son[now][1]]=fa[now];siz[fa[now]]--;int nxt=fa[now];Clear(now);splay(nxt);
}
void dfs(int x){
	if (son[x][0]) dfs(son[x][0]);
	cout<<val[x]<<" ";
	if (son[x][1]) dfs(son[x][1]);
}
void Main(){
	opt=read();x=read();
	if (opt==1) Insert(x);
	if (opt==2) Delete(x);
	if (opt==3) printf("%d\n",findrank(x)+1);
	if (opt==4) printf("%d\n",val[findval(x)]);
	if (opt==5) printf("%d\n",val[findpre(x)]);
	if (opt==6) printf("%d\n",val[findsuf(x)]);
	//cout<<"现在的中序遍历是:";
	//dfs(rt);puts("");
}
int main()
{
	Testing=read();
    for (;Testing;Testing--) Main();
	return 0;
}

文艺平衡树

void change(int x,int Fa,int dir){id++;val[id]=x;fre[id]=siz[id]=1;fa[id]=Fa;son[Fa][dir]=id;}
void Clear(int x){
	val[x]=siz[x]=fre[x]=fa[x]=son[x][0]=son[x][1]=0;
}
void modify(int x){
	siz[x]=siz[son[x][1]]*(son[x][1]>0)+siz[son[x][0]]*(son[x][0]>0)+fre[x];
}
int Gdir(int x){return (son[fa[x]][1]==x);}
void rotate(int x,int final){
	if (fa[x]==final) return ;
	int F1,F2,D1,D2;F1=fa[x];F2=fa[F1];D1=Gdir(x);
	if (F2!=0) son[F2][Gdir(F1)]=x;
	fa[x]=F2;fa[F1]=x;son[F1][D1]=son[x][D1^1];
	if (son[x][D1^1]) fa[son[x][D1^1]]=F1;son[x][D1^1]=F1;
	modify(F1);modify(x);
}
void splay(int x,int final){
	while (fa[x]!=final){
		if ((fa[fa[x]]!=final)&&(Gdir(fa[x])==Gdir(x))) rotate(fa[x],final);else rotate(x,final);
		rotate(x,final);}
	if (final==0)rt=x;
}
int findval(int x){
	int now=rt;
	while (1){
		if (siz[son[now][0]]>=x) now=son[now][0];
		else {
			x-=siz[son[now][0]];
			if (x<=fre[now]){splay(now,0);return now;}
			x-=fre[now];now=son[now][1];
		}
	}
}
void pushdown(int x){
	if (tag[x]){
		swap(son[x][0],son[x][1]);
		tag[son[x][0]]^=1;tag[son[x][1]]^=1;
		tag[x]=0;
	}
}
int findrank(int x){
	int tot=0,now=rt;
	while (now){
		if (val[now]>x) now=son[now][0];
		else {
			tot+=siz[son[now][0]];
			if (val[now]==x) break;
			tot+=fre[now];now=son[now][1];
		}
	}if (now!=0) splay(now,0);return tot;
}
int find(int x){
	int now=rt;
	while (1){
        pushdown(now);
   		if (siz[son[now][0]]>=x) now=son[now][0];
		else {
			x-=siz[son[now][0]];
			if (x<=fre[now]) return now;
			x-=fre[now];now=son[now][1];
		}
	}
}
void Insert(int x){
	if (rt==0){id++;val[id]=x;siz[id]=fre[id]=1;rt=id;return ;}
	int G=findrank(x);
	if (G==0){
		findval(1);
		if (x==val[rt]) {fre[rt]++;siz[rt]++;return ;}
		change(x,rt,0);splay(id,0);return ;}findval(G);
    if (son[rt][1]==0){change(x,rt,1);splay(id,0);return ;}
    int now=son[rt][1];
    while (son[now][0]) now=son[now][0];
    if (x==val[now]) {fre[now]++;siz[now]++;splay(now,0);return ;}change(x,now,0);splay(id,0);return ;
}
void print(int now){
	pushdown(now);
	if (son[now][0]) print(son[now][0]);
	if ((val[now]-1>=1)&&(val[now]-1<=n))printf("%d ",val[now]-1);
	if (son[now][1]) print(son[now][1]); 
} 
int main()
{
	n=read();m=read();
	for (i=1;i<=n+2;i++) Insert(i);
	for (i=1;i<=m;i++){
		l=read();r=read();l=find(l);r=find(r+2);
		splay(r,0);splay(l,rt);tag[son[son[rt][0]][1]]^=1; 
	} //son[rt][0]:1~r+1    l+1~r+1->l~r
	print(rt);
	return 0;
}

LCT

图论

虚树

先将关键点按照 dfn 排序,然后再将相邻两点的 lca 放入,再次按照 dfn 排序,然后每个点在虚树上的父亲就是这个点和他前驱的 lca

2-SAT

void tarjan(int x){
	dfn[x]=low[x]=++id;stak[++len]=x;exist[x]=true;
	for (int i=d[x];i;i=b[i])
	     if (dfn[a[i]]==0) tarjan(a[i]),low[x]=min(low[x],low[a[i]]);
	     else if (exist[a[i]]) low[x]=min(low[x],dfn[a[i]]);
	if (low[x]==dfn[x]){tot++;
	     while (stak[len]!=x) bel[stak[len]]=tot,exist[stak[len]]=false,len--;
	     bel[x]=tot;exist[x]=false;len--;
	}
}
int main()
{
	n=read();m=read();
	for (i=1;i<=m;i++){
		xa=read();xb=read();ya=read();yb=read();
		add(xa+(1-xb)*n,ya+yb*n);add(ya+(1-yb)*n,xa+xb*n);
		}
	for (i=1;i<=2*n;i++) if (dfn[i]==0) tarjan(i);
	for (i=1;i<=n;i++)
	    if (bel[i]==bel[i+n]) {puts("IMPOSSIBLE");return 0;}
	puts("POSSIBLE");
	for (i=1;i<=n;i++)
	    if (bel[i]<bel[i+n]) printf("0 ");else printf("1 ");
return 0;
}

点双连通分量

void add(int x,int y){
	cnt++;a[cnt]=y;b[cnt]=d[x];d[x]=cnt;
}
void tarjan(int x,int fa){
	dfn[x]=low[x]=++id;
	if ((x==rt)&&(d[x]==0)){
		tot++;vcc[tot].push_back(x);
		return ;	}
	stak[++len]=x;
	int num=0;
	for (int i=d[x];i;i=b[i])
	    if (a[i]!=fa)
	        if (dfn[a[i]]==0){
	        	tarjan(a[i],x);
	        	if (low[a[i]]>=dfn[x]){
	        		num++;tot++;
	        		while (stak[len]!=a[i]){
	        			vcc[tot].push_back(stak[len]);
	        			len--;
					}vcc[tot].push_back(stak[len]);len--;
					vcc[tot].push_back(x);
				}
				low[x]=min(low[x],low[a[i]]);
			}else low[x]=min(low[x],dfn[a[i]]);
   if ((num>=2)||((x!=rt)&&(num==1))) cut[x]=true;
}
int main()
{
	n=read();m=read();
	for (i=1;i<=m;i++){
		x=read();y=read();
		if (x==y) continue;
		add(x,y);add(y,x);
	}
	for (i=1;i<=n;i++)
	    if (dfn[i]==0) rt=i,tarjan(i,0);
	printf("%lld\n",tot);
	for (i=1;i<=tot;i++){
		printf("%lld ",vcc[i].size());
		for (j=0;j<vcc[i].size();j++)
		    printf("%lld ",vcc[i][j]);
		puts("");
	}
return 0;
}

边双连通分量

void add(int x,int y){
	cnt++;a[cnt]=y;b[cnt]=d[x];d[x]=cnt;
}
void tarjan(int x,int cht){
	dfn[x]=low[x]=++id;
	for (int i=d[x];i;i=b[i])
	         if (dfn[a[i]]==0){
	         	tarjan(a[i],i);
	         	if (low[a[i]]>low[x]) cut[i]=cut[i^1]=true;
				 low[x]=min(low[x],low[a[i]]);
			}
			else if (i!=(cht^1))low[x]=min(low[x],dfn[a[i]]);
}
void sc(int x,int cas){
	if (vis[x]) return ;
	vis[x]=true;siz[num]++;
	if (cas==1) printf("%d ",x);
	for (int i=d[x];i;i=b[i])
	     if (cut[i]==false)
	         sc(a[i],cas);
}
int main()
{
	n=read();m=read();cnt=1;
	for (i=1;i<=m;i++){
		x=read();y=read();
		add(x,y);add(y,x);
	}
	for (i=1;i<=n;i++) 
	    if (dfn[i]==0) tarjan(i,0);
	for (i=1;i<=n;i++)
	    if (vis[i]==false) num++,sc(i,0);
	for (i=1;i<=n;i++) vis[i]=false;
	printf("%lld\n",num);
	num=0;
	for (i=1;i<=n;i++)
	    if (vis[i]==false)
	        num++,printf("%d ",siz[num]),sc(i,1),puts("");
return 0;
}

二分图最大匹配(匈牙利算法)

bool sc(int x){
	for (int i=d[x];i;i=b[i])
	     if (vis[a[i]]==false){
	     	vis[a[i]]=true;
	     	if ((match[a[i]]==0)||(sc(match[a[i]]))){
	     		match[a[i]]=x;return true;
			 }
		 }
	return false;
}
int main()
{
	n=read();m=read();tx=read();
	for (i=1;i<=tx;i++){
		x=read();y=read();add(x,y+n);add(y+n,x);
	}
	for (i=1;i<=n;i++){
		for (j=1;j<=n+m;j++) vis[j]=false;
		if (sc(i)) ans++;
	}
	printf("%d\n",ans);
return 0;
}

差分约束

	n=read();m=read();
	for (i=1;i<=n;i++) add(0,i,0);
	for (i=1;i<=n;i++) f[i]=1e18;
	for (i=1;i<=m;i++){
		x=read();y=read();z=read();add(y,x,z);}
	t=1;w=1;
	while (t<=w){
		if (tag[f1[t]]>n+1){puts("NO");return 0;}
		for (i=d[f1[t]];i;i=b[i])
		     if (f[a[i]]>f[f1[t]]+c[i]){
		     	f[a[i]]=f[f1[t]]+c[i];tag[a[i]]++;w++;f1[w]=a[i];
			 }
		t++;
	}
	for (i=1;i<=n;i++) printf("%lld ",f[i]);

割点

void tarjan(int rt,int x){
	dfn[x]=low[x]=++id;int num=0;
	for (int i=d[x];i;i=b[i])
	    if (dfn[a[i]]==0) {
	    	tarjan(rt,a[i]);
	    	if (low[a[i]]>=dfn[x]) num++;low[x]=min(low[x],low[a[i]]);
		}else low[x]=min(low[x],dfn[a[i]]);
	if ((num>=2)||((num>=1)&&(x!=rt))) cut[x]=true;
}
int main()
{
	n=read();m=read();
	for (i=1;i<=m;i++) x=read(),y=read(),add(x,y),add(y,x);
	for (i=1;i<=n;i++) if (dfn[i]==0) tarjan(i,i);
	for (i=1;i<=n;i++)
	    if (cut[i]) tot++;
	printf("%d\n",tot);
	for (i=1;i<=n;i++)
	    if (cut[i]) printf("%d ",i);
return 0;
}

有向图缩点

void tarjan(int x){
	dfn[x]=++id;stak[++len]=x;low[x]=dfn[x];exist[x]=true;
	for (int i=d[x];i;i=b[i])
	    if (dfn[a[i]]==0) tarjan(a[i]),low[x]=min(low[x],low[a[i]]);
	    else if (exist[a[i]]) low[x]=min(low[x],dfn[a[i]]);
	if (low[x]==dfn[x]){tot++;
		while (stak[len]!=x){bel[stak[len]]=tot;V[tot]+=val[stak[len]];exist[stak[len]]=false;len--;}bel[x]=tot;V[tot]+=val[x];exist[x]=false;len--;
	}
}
int main()
{
	n=read();m=read();
	for (i=1;i<=n;i++) val[i]=read();
	for (i=1;i<=m;i++){x=read();y=read();add(x,y);edge[i].x=x,edge[i].y=y;}
	for (i=1;i<=n;i++) if (dfn[i]==0) tarjan(i);
	for (i=1;i<=m;i++)
	    if (bel[edge[i].x]!=bel[edge[i].y])
	         {
	          if (vis[make_pair(bel[edge[i].x],bel[edge[i].y])]) continue;
	          vis[make_pair(bel[edge[i].x],bel[edge[i].y])]=true;
	          E[bel[edge[i].x]].push_back(bel[edge[i].y]);deg[bel[edge[i].y]]++;
	          }t=1;
	for (i=1;i<=tot;i++)
	     if (deg[i]==0) {w++;f1[w]=i;Va[i]=V[i];}
	while (t<=w){
		for (i=0;i<E[f1[t]].size();i++){
			y=E[f1[t]][i];Va[y]=max(Va[y],Va[f1[t]]+V[y]);deg[y]--;
			if (deg[y]==0){w++;f1[w]=y;}
		}
		t++;
	}
	for (i=1;i<=tot;i++) ans=max(ans,Va[i]);
	printf("%lld\n",ans);
	return 0;
}

严格次小生成树

bool cmp(node a,node b){return a.c<b.c;}
int find(int x){
	if (f[x]!=x) f[x]=find(f[x]);return f[x];
}
void add(int x,int y,int z){cnt++;a[cnt]=y;b[cnt]=d[x];c[cnt]=z;d[x]=cnt;}
void build(int x,int fa){
	for (int i=d[x];i;i=b[i])
	     if (a[i]!=fa) {
	     	E1[a[i]][0]=c[i];Fa[a[i]][0]=x;E2[a[i]][0]=0;
			 for (int j=1;j<=20;j++) {
	     		E2[a[i]][j]=max(E2[a[i]][j-1],E2[a[i]][j-1]);
	     		if (E1[a[i]][j-1]!=E1[Fa[a[i]][j-1]][j-1]) E2[a[i]][j]=max(E2[a[i]][j],min(E1[a[i]][j-1],E1[Fa[a[i]][j-1]][j-1]));
				E1[a[i]][j]=max(E1[a[i]][j-1],E1[Fa[a[i]][j-1]][j-1]);
				Fa[a[i]][j]=Fa[Fa[a[i]][j-1]][j-1]; 
	     	}
	     	dep[a[i]]=dep[x]+1;
		 build(a[i],x);
	     }
}
long long calc1(long long x,long long y){
	if (dep[x]<dep[y]) swap(x,y);ans1=0;
	for (int i=20;i>=0;i--)
	     if (dep[Fa[x][i]]>=dep[y]) ans1=max(ans1,E1[x][i]),x=Fa[x][i];
	if (x==y) return ans1;
    for (int i=20;i>=0;i--)
        if (Fa[x][i]!=Fa[y][i]) ans1=max(ans1,E1[x][i]),ans1=max(ans1,E1[y][i]),x=Fa[x][i],y=Fa[y][i];
    ans1=max(ans1,max(E1[x][0],E1[y][0]));
    return ans1;
}
long long calc2(long long x,long long y){
	if (dep[x]<dep[y]) swap(x,y);ans2=0;
	for (int i=20;i>=0;i--)
	     if (dep[Fa[x][i]]>=dep[y]) {
	     	if (E1[x][i]!=now) ans2=max(ans2,E1[x][i]);
	     	else ans2=max(ans2,E2[x][i]);
	     	x=Fa[x][i];
	     }
	if (x==y) return ans2;
    for (int i=20;i>=0;i--)
        if (Fa[x][i]!=Fa[y][i]) {
        	if (E1[x][i]!=now) ans2=max(ans2,E1[x][i]);
        	else ans2=max(ans2,E2[x][i]);
        	if (E1[y][i]!=now) ans2=max(ans2,E1[y][i]);
        	else ans2=max(ans2,E2[y][i]);
        	x=Fa[x][i];y=Fa[y][i];
        }	
	if (E1[x][0]!=now) ans2=max(ans2,E1[x][0]);else ans2=max(ans2,E2[x][0]);
    if (E1[y][0]!=now) ans2=max(ans2,E1[y][0]);else ans2=max(ans2,E2[y][0]);
    return ans2;
}
int main()
{
	n=read();m=read();
	for (i=1;i<=m;i++) e[i].x=read(),e[i].y=read(),e[i].c=read();
	sort(e+1,e+m+1,cmp);
	for (i=1;i<=n;i++) f[i]=i;
	for (i=1;i<=m;i++){
		r1=find(e[i].x);r2=find(e[i].y);
		if (r1!=r2){tag[i]=true;tot+=e[i].c;add(e[i].x,e[i].y,e[i].c);add(e[i].y,e[i].x,e[i].c);f[r1]=r2;}
	}dep[1]=1;
	build(1,0);ans=1e18;
	for (i=1;i<=m;i++)
	   if (e[i].x!=e[i].y)
	    if (tag[i]==false){
	    	now=calc1(e[i].x,e[i].y);
	    	if (tot-now+e[i].c!=tot) ans=min(ans,tot-now+e[i].c);
	    	else {
	    		GG=calc2(e[i].x,e[i].y);
	    		ans=min(ans,tot-GG+e[i].c);
			}
		}
	printf("%lld\n",ans);
return 0;
}

负环

void Main(){
	n=read();m=read();cnt=0;
	for (i=1;i<=n;i++) d[i]=0;
	for (i=1;i<=m;i++){
		x=read();y=read();z=read();
		if (z>=0) add(x,y,z),add(y,x,z);else add(x,y,z);
	}
    for (i=1;i<=n;i++) f[i]=1e18;
    for (i=1;i<=n;i++) deg[i]=0;
	t=1;w=1;f1[1]=1;f[1]=0;
	while (t<=w){
		for (int i=d[f1[t]];i;i=b[i])
		      if (f[f1[t]]+c[i]<f[a[i]]){
		      	f[a[i]]=f[f1[t]]+c[i];deg[a[i]]++;
		      	w++;f1[w]=a[i];
		      	if (deg[a[i]]>=n+2){
		      		puts("YES");return ;
				  }
			  }
		t++;
	}	puts("NO");
}

计算几何

旋转卡壳

node operator +(const node &a,const node &b){return {a.x+b.x,a.y+b.y};}
node operator -(const node &a,const node &b){return {a.x-b.x,a.y-b.y};}
int operator *(const node &a,const node &b){return a.x*b.x+a.y*b.y;}
int operator ^(const node &a,const node &b){return a.x*b.y-a.y*b.x;}
long long dist(node a){return a.x*a.x+a.y*a.y;}
bool cmp(node x,node y){
	if (((x-a[1]^(y-a[1])))>0) return 1;
	if ((((x-a[1]^(y-a[1])))==0)&&(dist(x-a[1])<dist(y-a[1]))) return 1;
	return 0;
}
int main()
{
	n=read();minx=1e9;miny=1e9;
	for (i=1;i<=n;i++) {a[i].x=read();a[i].y=read();
		if ((a[i].x<minx)||((a[i].x==minx)&&(a[i].y<miny))) minx=a[i].x,miny=a[i].y,id=i;
	}
	swap(a[1],a[id]);sort(a+2,a+n+1,cmp);
	if (n==2){printf("%lld\n",dist(a[2]-a[1]));return 0;}
	w=1;b[1]=1;for (i=2;i<=n;i++)
	   if ((a[i].x!=a[i-1].x)||(a[i].y!=a[i-1].y))
	   {
		while ((w>2)&&(((a[i]-a[b[w]])^(a[b[w]]-a[b[w-1]]))>0)) w--;
		b[++w]=i;
	}
	for (i=1;i<=n;i++) a[i]=a[b[i]];
	n=w;
	a[0]=a[n];
	j=1; 
	for (i=0;i<=n;i++){
		while (((a[j]-a[(j+1) % (n+1)])^(a[(i+1) % (n+1)]-a[i]))>0) j=(j+1) % (n+1);
		ans=max(ans,dist(a[i]-a[j]));
		ans=max(ans,dist(a[(i+1) % (n+1)]-a[j]));
	}
	printf("%lld\n",ans);
return 0;
}

二维凸包

struct node{double x,y;} a[1001010];
double ans;
long long w,b[1001010],n,i;
node operator + (const node &a,const node &b){return (node){a.x+b.x,a.y+b.y};}
node operator - (const node &a,const node &b){return (node){a.x-b.x,a.y-b.y};}
double operator * (const node &a,const node &b){return a.x*b.x+a.y*b.y;}
double operator ^ (const node &a,const node &b){return a.x*b.y-a.y*b.x;}
double dist(node a){return sqrt(a.x*a.x+a.y*a.y);}
bool cmp(node a,node b){return ((a.x<b.x)||((a.x==b.x)&&(a.y<b.y)));}
int main()
{
	n=read();
	for (i=1;i<=n;i++) scanf("%lf%lf",&a[i].x,&a[i].y);
	sort(a+1,a+n+1,cmp);
	for (i=1;i<=n;i++){
		while ((w>1)&&(((a[i]-a[b[w-1]])^(a[b[w]]-a[b[w-1]]))>0)) w--;w++;b[w]=i;
	}
	for (i=2;i<=w;i++) ans+=dist(a[b[i]]-a[b[i-1]]);
	w=0;
	for (i=1;i<=n;i++){
		while ((w>1)&&(((a[i]-a[b[w-1]])^(a[b[w]]-a[b[w-1]]))<0)) w--;w++;b[w]=i;
	}
	for (i=2;i<=w;i++) ans+=dist(a[b[i]]-a[b[i-1]]);
    printf("%.2lf\n",ans);
return 0;
}

网络流

网络最大流

long long i,x,y,z,m,st,ed,n,t,w,a[1001010],cnt,ans,b[1001010],c[1001010],d[1001010],dep[1001010],dd[1001010],f1[10001010];
void add(int x,int y,int z){cnt++;a[cnt]=y;b[cnt]=d[x];c[cnt]=z;d[x]=cnt;}
bool bfs(){
	for (int i=1;i<=n;i++) dep[i]=0;
	t=1;w=1;dep[st]=1;f1[1]=st;dd[st]=d[st];
	while (t<=w){
		for (int i=dd[f1[t]];i;i=b[i])
		      if ((dep[a[i]]==0)&&(c[i]!=0)){
		      	dep[a[i]]=dep[f1[t]]+1;w++;f1[w]=a[i];dd[a[i]]=d[a[i]];
			  }
		t++;
	}
return dep[ed]>0;
}
long long dfs(int x,long long flow){
	if (x==ed) return flow;
	long long out=0,res;
	for (int i=dd[x];i&&flow;i=b[i]){
		dd[x]=i;
		if ((c[i]!=0)&&(dep[a[i]]==dep[x]+1)){
			res=dfs(a[i],min(c[i],flow));
			if (res==0) dep[a[i]]=0;
			c[i]-=res;c[i^1]+=res;flow-=res;out+=res;
		}
	}return out;
}
int main()
{
	n=read();m=read();cnt=1;st=read();ed=read();
	for (i=1;i<=m;i++) x=read(),y=read(),z=read(),add(x,y,z),add(y,x,0);
	while (bfs()) ans+=dfs(st,1e18);
	printf("%lld\n",ans);
return 0;
}

最小费用最大流

long long SPFA(){
	for (i=1;i<=n;i++) dis[i]=1e18,flow[i]=0;
	t=1;w=1;f1[1]=st;dis[st]=0;flow[st]=1e18;
	while (t<=w){
		for (int i=d[f1[t]];i;i=b[i])
		      if ((dis[a[i]]>dis[f1[t]]+c2[i])&&(c1[i]!=0)){
		      	dis[a[i]]=dis[f1[t]]+c2[i];
		      	flow[a[i]]=min(c1[i],flow[f1[t]]);
		      	fa[a[i]]=f1[t];val[a[i]]=i;
		      	w++;f1[w]=a[i];
			  }
		t++;
	}
	if (flow[ed]==0) return 0;
	for (i=ed;i;i=fa[i]) c1[val[i]]-=flow[ed],c1[val[i]^1]+=flow[ed];
	G1+=flow[ed];G2+=flow[ed]*dis[ed];
	return flow[ed];
}
int main()
{
	n=read();m=read();cnt=1;st=read();ed=read();
	for (i=1;i<=m;i++) x=read(),y=read(),z1=read(),z2=read(),add(x,y,z1,z2),add(y,x,0,-z2);
	while (1){
		now=SPFA();
		if (now==0) break;	}
		printf("%lld %lld\n",G1,G2);
return 0;
}

字符串

KMP

int main(){
	scanf("%s",S+1);n=strlen(S+1);scanf("%s",T+1);m=strlen(T+1);
	nxt[1]=0;
	for (i=2;i<=m;i++){
		while ((j>0)&&(T[i]!=T[j+1])) j=nxt[j];
		if (T[i]==T[j+1]) j++;nxt[i]=j;
	}j=0;
	for (i=1;i<=n;i++){
		while ((j>0)&&(S[i]!=T[j+1])) j=nxt[j];
		if (S[i]==T[j+1]) j++;
		if (j==m){printf("%d\n",i-m+1);j=nxt[j];} 
	}
	for (i=1;i<=m;i++) printf("%d ",nxt[i]);
}

Manacher

int main(){
	scanf("%s",S+1);n=strlen(S+1);T[1]='#';
	for (i=1;i<=n;i++) T[i*2]=S[i],T[i*2+1]='#';n=n*2+1;
	for (i=1;i<=n;i++) {
		if (i<=rit) lim[i]=min(rit-i+1,lim[mid-(i-mid)]);
		while ((i+lim[i]<=n)&&(lim[i]<i)&&(T[i+lim[i]]==T[i-lim[i]])) lim[i]++;
		if (i+lim[i]-1>rit) rit=i+lim[i]-1,mid=i;
		ans=max(ans,lim[i]-1); 
	}
	printf("%d\n",ans);
}

失配树

void add(int x,int y){cnt++;a[cnt]=y;b[cnt]=d[x];d[x]=cnt;} 
void build(int x,int fa){
   E[x][0]=fa;
   for (int i=1;i<=20;i++) E[x][i]=E[E[x][i-1]][i-1];
   for (int i=d[x];i;i=b[i])
        if (a[i]!=fa) dep[a[i]]=dep[x]+1,build(a[i],x);
} 
int lca(int x,int y){
	if (dep[x]<dep[y]) swap(x,y);
	for (int i=20;i>=0;i--) 
	    if (dep[E[x][i]]>=dep[y]) x=E[x][i];
	if (x==y) return x;
	for (int i=20;i>=0;i--)
	       if (E[x][i]!=E[y][i]) x=E[x][i],y=E[y][i];
	return E[x][0]; 
}
int main(){
	scanf("%s",S+1);n=strlen(S+1);
	for (i=2;i<=n;i++){
		while ((j>0)&&(S[i]!=S[j+1])) j=nxt[j];
		if (S[i]==S[j+1]) j++;nxt[i]=j;
	}
	for (i=1;i<=n;i++) add(nxt[i]+1,i+1);dep[1]=1;
	build(1,0);
	Testing=read();
	for (;Testing;Testing--){
		x=read();y=read();
		printf("%d\n",lca(nxt[x]+1,nxt[y]+1)-1);
	}
}

后缀数组

char S[1001010];
int tot,K,lst[1001010],B[1001010],sa[1001010],fre[1001010],rk[1001010],n,i,len,H[1001010];
void sort(){tot=0;
	for (i=n;i>n-len;i--) B[++tot]=i;
	for (i=1;i<=n;i++) if (sa[i]>len) B[++tot]=sa[i]-len;
	for (i=1;i<=n;i++) fre[rk[B[i]]]++;
	for (i=1;i<=max(n,250);i++) fre[i]=fre[i-1]+fre[i];
	for (i=n;i>=1;i--) sa[fre[rk[B[i]]]--]=B[i];
	for (i=0;i<=max(n,250);i++) fre[i]=0;
}
void Remake(){
	tot=0;
	for (i=1;i<=n;i++) lst[i]=rk[i];
	for (i=1;i<=n;i++)
	   if ((lst[sa[i]]==lst[sa[i-1]])&&(lst[sa[i]+len]==lst[sa[i-1]+len])) rk[sa[i]]=tot;
	   else rk[sa[i]]=++tot;
}
int main()
{
	scanf("%s",S+1);n=strlen(S+1);
	for (i=1;i<=n;i++) rk[i]=S[i];
	for (i=1;i<=n;i++) sa[i]=i;
	sort();Remake();
	for (len=1;len<=n;len<<=1) sort(),Remake();
    for (i=1;i<=n;i++){
    	H[rk[i]]=i;
    	if (K) K--;
    	while ((S[sa[rk[i]]+K]==S[sa[rk[i]-1]]+K)&&(K<=n)) K++;H[rk[i]]=K;
	}
    for (i=1;i<=n;i++) printf("%d ",sa[i]);
return 0;
}

Trie树

void insert(){
	now=0;
	for (int i=1;i<=m;i++){
		if (trie[now][S[i]-'a'+1]==0) trie[now][S[i]-'a'+1]=++cnt;
		now=trie[now][S[i]-'a'+1];
	}exist[now]=true;
}
void find(){
	now=0;
	for (int i=1;i<=m;i++){
		if (trie[now][S[i]-'a'+1]==0) {puts("WRONG");return ;}
		now=trie[now][S[i]-'a'+1];
	}if (exist[now]==false){puts("WRONG");return ;}
	tag[now]++;
	if (tag[now]==1) puts("OK");else puts("REPEAT");
}
int main()
{
	n=read();
	for (i=1;i<=n;i++){
		scanf("%s",S+1);m=strlen(S+1);insert();
	}
	Testing=read();
	for (i=1;i<=Testing;i++){
		scanf("%s",S+1);m=strlen(S+1);
		find();
	}
return 0;
}

DP

斜率优化

double slope(int x,int y){
	double sx=a[x],sy=f[x]+a[x]*a[x]+2*L*a[x];
	double tx=a[y],ty=f[y]+a[y]*a[y]+2*L*a[y];
	if ((sx==tx)) return 1e18;
	else return ((ty-sy)/(tx-sx));
}
int main()
{
	n=read();L=read();L++;
	for (i=1;i<=n;i++) a[i]=read();
	for (i=1;i<=n;i++) pre[i]=pre[i-1]+a[i];
	for (i=1;i<=n;i++) a[i]=pre[i]+i;
	l=1;r=1;q[1]=0;
	for (i=1;i<=n;i++){
		while ((l<r)&&(slope(q[l],q[l+1])<2*a[i])) l++;
		f[i]=f[q[l]]+(a[i]-a[q[l]]-L)*(a[i]-a[q[l]]-L);
		while ((l<r)&&(slope(q[r-1],q[r])>slope(q[r],i))) r--;
		q[++r]=i;
	}
   printf("%lld\n",f[n]);
return 0;
}

四边形不等式优化

任意 abcd 满足 w(a,d)+w(b,c)w(a,c)+w(b,d)w 满足四边形不等式

同样等价于 a<b 满足 w(a,b+1)+w(a+1,b)w(a,b)+w(a+1,b+1)

对于一个二维的 DP 方程式:

F(l,r)=mink=lr1F(l,k)+F(k+1,r)+w(l,r)

如果 w 满足四边形不等式并且 w(a,d)w(b,c),那么 F 满足四边形不等式。

如果 F 满足四边形不等式,记 P(l,r)F(l,r) 的决策点,则有:

P(l,r1)P(l,r)P(l+1,r)

int main()
{
	n=read();
	for (i=1;i<=n;i++) a[i]=read();
	for (i=n+1;i<=2*n;i++) a[i]=a[i-n];
	n=n*2;
	for (i=1;i<=n;i++) pre[i]=pre[i-1]+a[i];
	for (i=1;i<=n;i++)
	   for (j=1;j<=n;j++)
	       dp[i][j]=1e18;
	for (i=1;i<=n;i++) dp[i][i]=0,pos[i][i]=i;
	for (len=2;len<=n/2;len++)
	    for (lft=1;lft<=n-len+1;lft++){
	    	rit=lft+len-1;
	    	for (i=pos[lft][rit-1];i<=pos[lft+1][rit];i++)
	    	   if (i<rit)
	    	     if (dp[lft][i]+dp[i+1][rit]+pre[rit]-pre[lft-1]<dp[lft][rit]){
	    	     	dp[lft][rit]=dp[lft][i]+dp[i+1][rit]+pre[rit]-pre[lft-1];
	    	     	pos[lft][rit]=i;
				 }
	    }
	ans=1e18;
	for (i=1;i<=n/2;i++) ans=min(ans,dp[i][i+(n/2)-1]);
	printf("%lld\n",ans);
	for (i=1;i<=n;i++)
	   for (j=1;j<=n;j++)
	       dp[i][j]=0,pos[i][j]=0;
	for (i=1;i<=n;i++) dp[i][i]=0,pos[i][i]=i;
	for (len=2;len<=n/2;len++)
	    for (lft=1;lft<=n-len+1;lft++){
	    	rit=lft+len-1;
	    	for (i=lft;i<rit;i++)   
	    	     if (i<rit)
	    	     if (dp[lft][i]+dp[i+1][rit]+pre[rit]-pre[lft-1]>dp[lft][rit]){
	    	     	dp[lft][rit]=dp[lft][i]+dp[i+1][rit]+pre[rit]-pre[lft-1];
	    	     	pos[lft][rit]=i;
				 }
		}
	ans=0;
	for (i=1;i<=n/2;i++) ans=max(ans,dp[i][i+(n/2)-1]);
	printf("%lld\n",ans);
return 0;
}
/*
w(l,r)=sum(l,r)
a<=b<=c<=d
w(a,d)+w(b,c)=pre[d]-pre[a-1]+pre[c]-pre[b-1]
w(a,c)+w(b,d)=pre[d]+pre[c]-pre[a-1]-pre[b-1]
w(a,d)+w(b,c)=w(a,c)+w(b,d) Âú×ãËıßÐβ»µÈʽ
w(a,d)>=w(b,c)
ËùÒÔFÂú×ãËıßÐβ»µÈʽ
ËùÒÔP(l,r-1)<=P(l,r)<=P(l+1,r) 
°´ÕÕ³¤¶Èö¾Ù¼´¿É¡£ 
×î´óÖµÔòÎÞ·¨Ê¹Ó㬲»Âú×ãËıßÐβ»µÈʽ 
*/

搜索

Others

整体二分

void modify(int x,int y){
	for (;x<=n;x+=x&-x) tree[x]+=y;
}
long long query(long long x){
	long long ans=0;
	for (;x;x-=x&-x) ans+=tree[x];
	return ans;
}
void solve(long long tl,long long tr,int st,int ed){
	if (tl>tr) return ;
	if (st>ed) return ;
	if (tl==tr){
		
		for (int i=st;i<=ed;i++)
		    if (q[i].opt==1) Answer[q[i].num]=tl;
		return ;
	}
	long long mid=(tl+tr)>>1;
	int nl=st,nr=ed;
	for (int i=st;i<=ed;i++)
	    if (q[i].opt==0){
	    	if (q[i].pos<=mid) qt[nl++]=q[i],modify(q[i].num,q[i].val);
	    	else qt[nr--]=q[i];
		}
		else {
			int num=query(q[i].r)-query(q[i].l-1);
			if (num>=q[i].val) qt[nl++]=q[i];
			else q[i].val-=num,qt[nr--]=q[i];
		}
	for (int i=st;i<=ed;i++)
	    if ((q[i].opt==0)&&(q[i].pos<=mid)) modify(q[i].num,-q[i].val);
	for (int i=st;i<nl;i++) q[i]=qt[i];
	for (int i=nr+1;i<=ed;i++) q[i]=qt[ed-i+1+nr];
	solve(tl,mid,st,nl-1);
	solve(mid+1,tr,nr+1,ed);
}
int main()
{
	n=read();M=read();
	for (i=1;i<=n;i++){
		x=read();
		e[i]=x;
		q[++id].opt=0;
		q[id].pos=x;
		q[id].num=i;
		q[id].val=1;
	}
	for (i=1;i<=M;i++){
		opt=getchar();
		while ((opt!='C')&&(opt!='Q')) opt=getchar();
		if (opt=='Q'){
			vis[i]=true;
			l=read();r=read();k=read();
			q[++id].opt=1;
			q[id].l=l;
			q[id].r=r;
			q[id].val=k;
			q[id].num=i;
		}
		if (opt=='C'){
			x=read();y=read();
			q[++id].opt=0;
			q[id].pos=e[x];
			q[id].num=x;
			q[id].val=-1;
			q[++id].opt=0;
			q[id].pos=y;
			q[id].num=x;
			q[id].val=1;
			e[x]=y;
		}
	}
	solve(0,1e9,1,id);
	
	for (i=1;i<=M;i++) if (vis[i]) printf("%lld\n",Answer[i]);
	return 0;
}

模拟退火

#define urd uniform_real_distribution
mt19937 rnd(20060617);
long long i,n,m,ans;
double R,a[1001010],b[1001010],c[1001010],d[1001010],e[1001010];
double calc(double x,double y){
	double r=R;
	for (int i=1;i<=n;i++){
		double dis=sqrt((x-a[i])*(x-a[i])+(y-b[i])*(y-b[i]));
		r=min(r,dis-c[i]);
	}
	r=max(r,(double)0);
	int num=0;
	double mn=1e12;
	for (int i=1;i<=m;i++){
		double dis=sqrt((x-d[i])*(x-d[i])+(y-e[i])*(y-e[i]));
		mn=min(mn,dis-r);
		if (dis<=r) num++;
	}
	ans=max(ans,(long long)num);
	return -max(mn,(double)0)*14.14+num;
}
void Run(double st,double ed,double delta){
	double x=0,y=0;
	double res=calc(x,y);
	for (;st>=ed;st=st*delta){
		double nx=x+urd<>(-10,10)(rnd)*st;
		double ny=y+urd<>(-10,10)(rnd)*st;
	    double now=calc(nx,ny);
//	    printf("%lf %lf %lf\n",&nx,&ny,&now);
	    if ((now>res)||(exp((now-res)/st)>=urd<>(0,1)(rnd))) x=nx,y=ny,res=now;
	}
}
int main()
{
	n=read();m=read();scanf("%lf",&R);
	for (i=1;i<=n;i++) scanf("%lf%lf%lf",&a[i],&b[i],&c[i]);
	for (i=1;i<=m;i++) scanf("%lf%lf",&d[i],&e[i]);
	Run(1e12,1e-8,0.9996);
//	rnd=mt19937(time(0));
	Run(1e12,1e-8,0.9996);
	rnd=mt19937(12);
	Run(1e12,1e-8,0.9996);
	printf("%lld\n",ans);
	return 0;
}

可持久化并查集

int build(int x,int l,int r){
	int now=++id;
	if (l==r){
		tree[now].fa=l;
		tree[now].hgt=1;
		return now;
	}
	int mid=(l+r)>>1;
	tree[now].lft=build(x<<1,l,mid);
	tree[now].rit=build(x<<1|1,mid+1,r);
	return now;
}
int queryfa(int x,int l,int r,int pos){
	if (l==r) return tree[x].fa;
	int mid=(l+r)>>1;
	if (pos<=mid) return queryfa(tree[x].lft,l,mid,pos);
	else return queryfa(tree[x].rit,mid+1,r,pos);
}
int queryhgt(int x,int l,int r,int pos){
	if (l==r) return tree[x].hgt;
	int mid=(l+r)>>1;
	if (pos<=mid) return queryhgt(tree[x].lft,l,mid,pos);
	else return queryhgt(tree[x].rit,mid+1,r,pos);
}
int changefa(int x,int l,int r,int pos,int val){
	int now=++id;
	if (l==r){
		tree[now].fa=val;
		tree[now].hgt=tree[x].hgt;
		return now;
	}
	int mid=(l+r)>>1;
	if (pos<=mid) tree[now].lft=changefa(tree[x].lft,l,mid,pos,val);
	else tree[now].lft=tree[x].lft;
	if (pos>mid) tree[now].rit=changefa(tree[x].rit,mid+1,r,pos,val);
	else tree[now].rit=tree[x].rit;
	return now;
}
int changehgt(int x,int l,int r,int pos,int val){
	int now=++id;
	if (l==r){
		tree[now].fa=tree[x].fa;
		tree[now].hgt=val;
		return now;
	}
	int mid=(l+r)>>1;
	if (pos<=mid) tree[now].lft=changehgt(tree[x].lft,l,mid,pos,val);
	else tree[now].lft=tree[x].lft;
	if (pos>mid) tree[now].rit=changehgt(tree[x].rit,mid+1,r,pos,val);
	else tree[now].rit=tree[x].rit;
	return now;
}
int find(int nowrt,int x){
	while (queryfa(nowrt,1,n,x)!=x)
	     x=queryfa(nowrt,1,n,x);
	    return x;
}
void merge(int x,int y){
	int r1=find(rt[now],x);
	int r2=find(rt[now],y);
	if (r1==r2) return ;
	int h1=queryhgt(rt[now],1,n,r1);
	int h2=queryhgt(rt[now],1,n,r2);
	if (h1<h2){
		rt[now]=changefa(rt[now],1,n,r1,r2);
		return ;
	}
	if (h1>h2){
		rt[now]=changefa(rt[now],1,n,r2,r1);
		return ;
	}
	if (h1==h2){
		rt[now]=changefa(rt[now],1,n,r1,r2);
		rt[now]=changehgt(rt[now],1,n,r2,h1+1);
		return ;
	}
}
int main()
{
	n=read();m=read();
	for (i=1;i<=n;i++) fa[i]=i;
	for (i=1;i<=n;i++) hgt[i]=1;
	rt[0]=build(1,1,n);
	for (now=1;now<=m;now++){
		rt[now]=rt[now-1];
		opt=read();
		if (opt==1){
			x=read();y=read();
			merge(x,y);
		}
		if (opt==2){
		  bac=read();
		  rt[now]=rt[bac];
		}
		if (opt==3){
			x=read();y=read();
			r1=find(rt[now],x);r2=find(rt[now],y);
			if (r1==r2) puts("1");
			else puts("0");
		}
	}
return 0;
}

前缀优化建图

void add(int x,int y){
	cnt++;a[cnt]=y;b[cnt]=d[x];d[x]=cnt;
}
void tarjan(int x){
	dfn[x]=low[x]=++id;stak[++len]=x;exist[x]=true;
	for (int i=d[x];i;i=b[i])
	     if (dfn[a[i]]==0){
	     	tarjan(a[i]);
	     	low[x]=min(low[x],low[a[i]]);
			  }
			else if (exist[a[i]]) low[x]=min(low[x],low[a[i]]);
	if (low[x]==dfn[x]){
		tot++;
		while (stak[len]!=x){
			bel[stak[len]]=tot;
			exist[stak[len]]=false;
			len--;
		}
		bel[stak[len]]=tot;exist[stak[len]]=false;len--;
	}
}
int main()
{
	n=read();m=read();K=read();
	for (i=1;i<=m;i++){
		x=read();y=read();
		add(x+n,y);add(y+n,x);
	}
	id=2*n;
	for (now=1;now<=K;now++){
		tz=read();
		for (i=1;i<=tz;i++) uid[i]=read();
		for (i=1;i<=tz;i++) up[i]=++id;
		for (i=1;i<=tz;i++) down[i]=++id;
		for (i=1;i<tz;i++) add(up[i],up[i+1]);
		for (i=1;i<tz;i++) add(down[i+1],down[i]);
		for (i=1;i<=tz;i++) add(uid[i],up[i]);
		for (i=1;i<=tz;i++) add(down[i],uid[i]+n);
		for (i=1;i<tz;i++) add(up[i],uid[i+1]+n);
		for (i=2;i<=tz;i++) add(uid[i],down[i-1]);
	}
	tn=id;id=0;
	for (i=1;i<=n;i++)
	    if (dfn[i]==0) tarjan(i);
	for (i=1;i<=n;i++)
	    if (bel[i]==bel[i+n]){
	    	puts("NIE");
	    	return 0;
		}
	puts("TAK");
return 0;
}

FWT

void FWTOR(long long *a,long long opt){
	for (int i=1;i<n;i<<=1)
	   for (int j=0;j<n;j+=(i<<1))
	      for (int k=0;k<i;k++)
	          a[i+j+k]=(a[i+j+k]+a[j+k]*opt) % MOD;
}
void FWTAND(long long *a,long long opt){
	for (int i=1;i<n;i<<=1)
	   for (int j=0;j<n;j+=(i<<1))
	      for (int k=0;k<i;k++)
	          a[j+k]=(a[j+k]+a[i+j+k]*opt) % MOD;
}
void FWTXOR(long long *a,long long opt){
	for (int i=1;i<n;i<<=1)
	   for (int j=0;j<n;j+=(i<<1))
	      for (int k=0;k<i;k++){
	      	long long u=a[j+k],v=a[i+j+k];
	      	a[j+k]=(u+v)*opt % MOD;a[i+j+k]=(u-v+MOD)*opt % MOD;
	      }
}
int main()
{
	N=read();n=1;for (i=1;i<=N;i++) n=n*2;MOD=998244353;
	for (i=0;i<n;i++) A[i]=read(),lsta[i]=A[i];
	for (i=0;i<n;i++) B[i]=read(),lstb[i]=B[i];
	FWTOR(A,1);FWTOR(B,1);for (i=0;i<n;i++) C[i]=A[i]*B[i] % MOD;FWTOR(C,MOD-1);
	for (i=0;i<n;i++) printf("%lld ",C[i]);puts("");
	for (i=0;i<n;i++) A[i]=lsta[i],B[i]=lstb[i];FWTAND(A,1);FWTAND(B,1);for (i=0;i<n;i++) C[i]=A[i]*B[i] % MOD;FWTAND(C,MOD-1);
	for (i=0;i<n;i++) printf("%lld ",C[i]);puts("");
	for (i=0;i<n;i++) A[i]=lsta[i],B[i]=lstb[i];FWTXOR(A,1);FWTXOR(B,1);for (i=0;i<n;i++) C[i]=A[i]*B[i] % MOD;FWTXOR(C,(MOD+1)/2);
	for (i=0;i<n;i++) printf("%lld ",C[i]);puts("");
	return 0;
}

子集卷积

void FWTOR (int *a,int opt){
	for (int i=1;i<n;i<<=1)
	  for (int j=0;j<n;j+=(i<<1))
	     for (int k=0;k<i;k++){
	     	int now=0;
	     	if (opt==1) now=a[j+k];else now=MOD-a[j+k];
	     	a[j+k+i]+=now;if (a[j+k+i]>=MOD) a[j+k+i]-=MOD;
		 }
}
int main()
{
	N=read();n=1;for (i=1;i<=N;i++) n=n*2;MOD=1e9+9;
	for (i=1;i<=n;i++) fre[i]=(fre[i^(i&-i)])+1;
	for (i=0;i<n;i++) A[fre[i]][i]=read();
	for (i=0;i<n;i++) B[fre[i]][i]=read();
	for (i=0;i<=N;i++) FWTOR(A[i],1),FWTOR(B[i],1);
	for (i=0;i<n;i++)
	  for (j=0;j<=N;j++)
	      if (A[j][i])
	         for (k=0;k+j<=N;k++)
	             C[j+k][i]=(C[j+k][i]+(long long) A[j][i]*(long long)B[k][i]) % MOD;
	for (i=0;i<=N;i++) FWTOR(C[i],MOD-1);
	for (i=0;i<n;i++) printf("%d ",C[fre[i]][i]);
return 0;
}

多项式(myee)

Code
#include <algorithm>
#include <stdio.h>
#include <vector>
typedef long long llt;
typedef unsigned uint;typedef unsigned long long ullt;
typedef bool bol;typedef char chr;typedef void voi;
typedef double dbl;
template<typename T>bol _max(T&a,T b){return(a<b)?a=b,true:false;}
template<typename T>bol _min(T&a,T b){return(b<a)?a=b,true:false;}
template<typename T>T lowbit(T n){return n&-n;}
template<typename T>T gcd(T a,T b){return b?gcd(b,a%b):a;}
template<typename T>T lcm(T a,T b){return(a!=0||b!=0)?a/gcd(a,b)*b:(T)0;}
template<typename T>T exgcd(T a,T b,T&x,T&y){if(b!=0){T ans=exgcd(b,a%b,y,x);y-=a/b*x;return ans;}else return y=0,x=1,a;}
template<typename T>T power(T base,T index,T mod)
{
    T ans=1%mod;
    while(index)
    {
        if(index&1)ans=ans*base%mod;
        base=base*base%mod,index>>=1;
    }
    return ans;
}
namespace ConstMod
{
    template<const ullt p>
    class mod_ullt
    {
        private:
            ullt v;
            inline ullt chg(ullt w){return(w<p)?w:w-p;}
            inline mod_ullt _chg(ullt w){mod_ullt ans;ans.v=(w<p)?w:w-p;return ans;}
        public:
            mod_ullt():v(0){}
            mod_ullt(ullt v):v(v%p){}
            bol empty(){return!v;}
            inline ullt val(){return v;}
            friend bol operator<(mod_ullt a,mod_ullt b){return a.v<b.v;}
            friend bol operator>(mod_ullt a,mod_ullt b){return a.v>b.v;}
            friend bol operator<=(mod_ullt a,mod_ullt b){return a.v<=b.v;}
            friend bol operator>=(mod_ullt a,mod_ullt b){return a.v>=b.v;}
            friend bol operator==(mod_ullt a,mod_ullt b){return a.v==b.v;}
            friend bol operator!=(mod_ullt a,mod_ullt b){return a.v!=b.v;}
            inline friend mod_ullt operator+(mod_ullt a,mod_ullt b){return a._chg(a.v+b.v);}
            inline friend mod_ullt operator-(mod_ullt a,mod_ullt b){return a._chg(a.v+a.chg(p-b.v));}
            inline friend mod_ullt operator*(mod_ullt a,mod_ullt b){return a.v*b.v;}
            friend mod_ullt operator/(mod_ullt a,mod_ullt b){return b._power(p-2)*a.v;}
            friend mod_ullt operator^(mod_ullt a,ullt b){return a._power(b);}
            inline mod_ullt operator-(){return _chg(p-v);}
            mod_ullt sqrt()
            {
                if(power(v,(p-1)>>1,p)!=1)return 0;
                mod_ullt b=1;do b++;while(b._power((p-1)>>1)==1);
                ullt t=p-1,s=0,k=1;while(!(t&1))s++,t>>=1;
                mod_ullt x=_power((t+1)>>1),e=_power(t);
                while(k<s)
                {
                    if(e._power(1llu<<(s-k-1))!=1)x*=b._power((1llu<<(k-1))*t);
                    e=_power(p-2)*x*x,k++;
                }
                return _min(x,-x),x;
            }
            mod_ullt inv(){return _power(p-2);}
            mod_ullt _power(ullt index){mod_ullt ans(1),w(v);while(index){if(index&1)ans*=w;w*=w,index>>=1;}return ans;}
            voi read(){v=0;chr c;do c=getchar();while(c>'9'||c<'0');do v=(c-'0'+v*10)%p,c=getchar();while(c>='0'&&c<='9');v%=p;}
            voi print()
            {
                static chr C[20];uint tp=0;
                ullt w=v;do C[tp++]=w%10+'0',w/=10;while(w);
                while(tp--)putchar(C[tp]);
            }
            voi println(){print(),putchar('\n');}
            mod_ullt operator++(int){mod_ullt ans=*this;return v=chg(v+1),ans;}
        public:
            inline ullt&operator()(){return v;}
            inline mod_ullt&operator+=(mod_ullt b){return*this=_chg(v+b.v);}
            inline mod_ullt&operator-=(mod_ullt b){return*this=_chg(v+chg(p-b.v));}
            inline mod_ullt&operator*=(mod_ullt b){return*this=v*b.v;}
            mod_ullt&operator^=(ullt b){return*this=_power(b);}
            mod_ullt&operator/=(mod_ullt b){return*this=b._power(p-2)*v;}
            mod_ullt&operator++(){return v=chg(v+1),*this;}
    };
}
namespace NTT_POLY
{
    template<const ullt p,const ullt g>
    class poly_NTT
    {
        public:
            typedef ConstMod::mod_ullt<p>modint;
            typedef std::vector<modint>modvec;
        private:
            modvec V;
        public:
            class NTT
            {
                private:
                    uint n;uint*T;modint*G;
                public:
                    NTT():n(0),T(NULL),G(NULL){}
                    NTT(uint len)
                    {
                        n=1;while(n<len)n<<=1;
                        T=new uint[n],G=new modint[n],T[0]=0,G[0]=1;
                        for(uint i=1;i<n;i++)T[i]=((i&1)?n|T[i>>1]:T[i>>1])>>1;
                        modint w=power(g,(p-1)/n,p),*End=G+n;
                        for(modint*_G=G+1;_G<End;_G++)*_G=_G[-1]*w;
                    }
                    ~NTT(){if(T!=NULL)delete[]T,delete[]G,T=NULL,G=NULL;}
                    inline uint size(){return n;}
                    voi bzr(uint len)
                    {
                        n=1;while(n<len)n<<=1;
                        if(T!=NULL)delete[]T,delete[]G;
                        T=new uint[n],G=new modint[n],T[0]=0,G[0]=1;
                        for(uint i=1;i<n;i++)T[i]=((i&1)?n|T[i>>1]:T[i>>1])>>1;
                        modint w=power(g,(p-1)/n,p),*End=G+n;
                        for(modint*_G=G+1;_G<End;_G++)*_G=_G[-1]*w;
                    }
                    voi ntt(modvec&x,bol op)
                    {
                        if(x.size()<n)x.resize(n);
                        for(uint i=0;i<n;i++)if(T[i]<i)std::swap(x[i],x[T[i]]);
                        for(uint i=1;i<n;i<<=1)for(uint j=0;j<n;j+=i<<1)
                        {
                            modint*w=G;
                            for(uint k=0;k<i;k++,w+=n/(2*i))
                            {
                                modint t=x[i+j+k]*(*w);
                                x[i+j+k]=x[j+k]-t,x[j+k]+=t;
                            }
                        }
                        if(op)
                        {
                            for(uint i=1;i*2<n;i++)std::swap(x[i],x[n-i]);
                            modint t=modint(n).inv();for(uint i=0;i<n;i++)x[i]*=t;
                        }
                    }
                    inline modint Omega(uint n){return G[n%size()];}
                    NTT&operator=(NTT b)
                    {
                        if(T!=NULL)delete[]T,delete[]G,T=NULL,G=NULL;
                        if(b.T==NULL)return*this;
                        T=new uint[n],G=new modint[n=b.n];
                        for(uint i=0;i<n;i++)T[i]=b.T[i],G[i]=b.G[i];
                        return*this;
                    }
            };
            class DIFDIT
            {
                private:
                    uint n;modint*G;
                public:
                    DIFDIT():n(0),G(NULL){}
                    DIFDIT(uint len)
                    {
                        n=1;while(n<len)n<<=1;
                        G=new modint[n],G[0]=1;
                        modint w=power(g,(p-1)/n,p),*End=G+n;
                        for(modint*_G=G+1;_G<End;_G++)*_G=_G[-1]*w;
                    }
                    ~DIFDIT(){if(G!=NULL)delete[]G,G=NULL;}
                    inline uint size(){return n;}
                    voi bzr(uint len)
                    {
                        n=1;while(n<len)n<<=1;
                        if(G!=NULL)delete[]G;
                        G=new modint[n],G[0]=1;
                        modint w=power(g,(p-1)/n,p),*End=G+n;
                        for(modint*_G=G+1;_G<End;_G++)*_G=_G[-1]*w;
                    }
                    voi dif(modvec&x)
                    {
                        if(x.size()<n)x.resize(n);
                        for(uint i=n>>1;i;i>>=1)for(uint j=0;j<n;j+=i<<1) 
                        {
                            modint*w=G;
                            for(uint k=0;k<i;k++,w+=n/(2*i))
                            {
                                modint u=x[j+k],t=x[i+j+k];
                                x[j+k]=u+t,x[i+j+k]=(u-t)*(*w);
                            }
                        }
                    }
                    voi dit(modvec&x)
                    {
                        if(x.size()<n)x.resize(n);
                        for(uint i=1;i<n;i<<=1)for(uint j=0;j<n;j+=i<<1)
                        {
                            modint*w=G;
                            for(uint k=0;k<i;k++,w+=n/(2*i))
                            {
                                modint t=x[i+j+k]*(*w);
                                x[i+j+k]=x[j+k]-t,x[j+k]+=t;
                            }
                        }
                        for(uint i=1;i*2<n;i++)std::swap(x[i],x[n-i]);
                        modint t=modint(n).inv();for(uint i=0;i<n;i++)x[i]*=t;
                    } 
                    DIFDIT&operator=(DIFDIT b)
                    {
                        if(G!=NULL)delete[]G,G=NULL;
                        if(b.G==NULL)return*this;
                        G=new modint[n=b.n];
                        for(uint i=0;i<n;i++)G[i]=b.G[i];
                        return*this;
                    }
            };
        public:
            poly_NTT(){}
            poly_NTT(uint n){V.resize(n);}
            poly_NTT(modvec V):V(V){}
            inline voi bzr(){V.clear();}
            inline voi push(modint v){V.push_back(v);}
            inline voi pop(){V.pop_back();}
            inline voi cut_zero(){while(!V.empty()&&V.back().empty())V.pop_back();}
            inline voi chg_siz(uint n){V.resize(n);}
            inline voi chg_deg(uint n){V.resize(n+1);}
            inline bol empty(){return cut_zero(),V.empty();}
            inline uint size(){return V.size();}
            inline uint deg(){return V.size()-1;}
            inline modint val(uint n){return(n<size())?V[n]:0;}
            inline modvec GET(){return V;}
            poly_NTT reverse()
            {
                poly_NTT ans;for(uint i=size()-1;~i;i--)ans.push(V[i]);
                return ans;
            }
            friend poly_NTT operator+(poly_NTT a,poly_NTT b)
            {
                if(a.size()<b.size())a.chg_siz(b.size());
                for(uint i=0;i<b.size();i++)a[i]+=b[i];
                a.cut_zero();return a;
            }
            friend poly_NTT operator+(poly_NTT a,modint v)
            {
                if(!a.size())a.chg_siz(1);
                a[0]+=v;return a;
            }
            friend poly_NTT operator+(modint v,poly_NTT a)
            {
                if(!a.size())a.chg_siz(1);
                a[0]+=v;return a;
            }
            friend poly_NTT operator-(poly_NTT a){return a*modint(p-1);}
            friend poly_NTT operator-(poly_NTT a,poly_NTT b)
            {
                if(a.size()<b.size())a.chg_siz(b.size());
                for(uint i=0;i<b.size();i++)a[i]-=b[i];
                a.cut_zero();return a;
            }
            friend poly_NTT operator-(poly_NTT a,modint v)
            {
                if(!a.size())a.chg_siz(1);
                a[0]-=v;return a;
            }
            friend poly_NTT operator-(modint v,poly_NTT a)
            {
                if(!a.size())a.chg_siz(1);
                a[0]-=v;return-a;
            }
            friend poly_NTT operator*(poly_NTT a,poly_NTT b)
            {
                modvec&A=a.V,&B=b.V;DIFDIT s(A.size()+B.size());
                s.dif(A),s.dif(B);for(uint i=0;i<s.size();i++)A[i]*=B[i];
                s.dit(A),a.cut_zero();return a;
            }
            friend poly_NTT operator*(poly_NTT A,modint b)
            {
                for(auto&s:A.V)s*=b;
                return A;
            }
            friend poly_NTT operator*(modint b,poly_NTT A)
            {
                for(auto&s:A.V)s*=b;
                return A;
            }
            friend poly_NTT operator<<(poly_NTT a,uint k)
            {
                poly_NTT ans;ans.chg_siz(k);for(auto v:a.V)ans.push(v);
                return ans;
            }
            friend poly_NTT operator>>(poly_NTT a,uint k)
            {
                poly_NTT ans;for(uint i=k;i<a.size();i++)ans.push(a[i]);
                return ans;
            }
            friend poly_NTT sub_mul(poly_NTT a,poly_NTT b)
            {
                uint len=(a=a.reverse()).size();
                modvec&A=a.V,&B=b.V;
                DIFDIT s(len+B.size());
                s.dif(A),s.dif(B);for(uint i=0;i<s.size();i++)A[i]*=B[i];
                s.dit(A),a.chg_siz(len),a=a.reverse();return a;
            }
            poly_NTT inv(){return inv(size());}
            poly_NTT inv(uint prec)
            {
                modvec ans;DIFDIT s;ans.push_back(V[0].inv());
                for(uint tp=1;tp<prec;tp<<=1)
                {
                    modvec f(tp<<1),t=ans;
                    for(uint i=0;i<(tp<<1);++i)f[i]=val(i);
                    s.bzr(tp<<1),s.dif(f),s.dif(t);
                    for(uint i=0;i<(tp<<1);++i)f[i]=1-f[i]*t[i];
                    s.dit(f);
                    for(uint i=0;i<tp;++i)f[i]=f[i+tp],f[i+tp]=0;
                    s.dif(f);
                    for(uint i=(tp<<1)-1;~i;--i)f[i]*=t[i];
                    s.dit(f),ans.resize(tp<<1);
                    for(uint i=0;i<tp;++i)ans[i+tp]=f[i];
                }
                ans.resize(prec);return ans;
            }
            poly_NTT sqrt(){return sqrt(size());}
            poly_NTT sqrt(uint prec)
            {
                modvec ans,Inv;ans.push_back(val(0).sqrt()),Inv.push_back(ans[0].inv());
                DIFDIT s;
                modint w=modint(2).inv();
                for(uint tp=1;tp<prec;tp<<=1)
                {
                    s.bzr(tp<<2);
                    modvec f(tp<<1);for(uint i=0;i<(tp<<1);i++)f[i]=val(i);
                    s.dif(Inv);s.dif(ans);
                    for(uint i=0;i<(tp<<2);i++)Inv[i]*=2-Inv[i]*ans[i];
                    s.dit(Inv),Inv.resize(tp);s.dif(Inv);
                    for(uint i=0;i<(tp<<2);i++)Inv[i]*=2-Inv[i]*ans[i];
                    s.dit(Inv),Inv.resize(tp<<1);
                    modvec user=Inv;s.dif(Inv),s.dif(f);
                    for(uint i=0;i<(tp<<2);i++)ans[i]=(ans[i]+Inv[i]*f[i])*w;
                    s.dit(ans),Inv=user,ans.resize(tp<<1);
                }
                ans.resize(prec);return ans;
            }
            poly_NTT diff()
            {
                poly_NTT ans;for(uint i=1;i<size();i++)ans.push(i*V[i]);
                return ans;
            }
            poly_NTT inte()
            {
                if(!size())return*this;
                poly_NTT ans(size()+1);ans[1]=1;
                for(uint i=2;i<=size();i++)ans[i]=-ans[p%i]*(p/i);
                for(uint i=1;i<=size();i++)ans[i]*=V[i-1];
                return ans;
            }
            poly_NTT ln(){return ln(size());}
            poly_NTT ln(uint prec)
            {
                poly_NTT a=this->diff()*this->inv(prec);a.chg_siz(prec),a=a.inte(),a.chg_siz(prec);return a;
            }
            poly_NTT exp(){return exp(size());}
            poly_NTT exp(uint prec)
            {
                poly_NTT ans;modvec Inv;ans.push(1),Inv.push_back(1);
                for(uint tp=1;tp<prec;tp<<=1)
                {
                    modvec f,ff=ans.diff().V;
                    for(uint i=0;i<(tp<<1);i++)f.push_back(val(i));
                    f[0]=1;DIFDIT s(tp<<2);s.dif(ans.V),s.dif(Inv);
                    for(uint i=0;i<(tp<<2);i++)Inv[i]*=2-Inv[i]*ans[i];
                    s.dit(Inv),Inv.resize(tp);s.dif(Inv);
                    for(uint i=0;i<(tp<<2);i++)Inv[i]*=2-Inv[i]*ans[i];
                    s.dit(Inv),Inv.resize(tp<<1);s.dif(Inv);s.dif(ff);
                    for(uint i=0;i<(tp<<2);i++)ff[i]*=Inv[i];
                    s.dit(ff);f=(f-poly_NTT(ff).inte()).V;s.dif(f);
                    for(uint i=0;i<(tp<<2);i++)ans[i]*=f[i];
                    s.dit(Inv),s.dit(ans.V),ans.chg_siz(tp<<1);
                }
                ans.chg_siz(prec);return ans;
            }
            friend poly_NTT operator/(poly_NTT a,poly_NTT b)
            {
                a.cut_zero(),b.cut_zero();if(a.size()<b.size())return poly_NTT();
                poly_NTT ans=a.reverse()*b.reverse().inv(a.size()-b.size()+1);
                ans.chg_siz(a.size()-b.size()+1);return ans.reverse();
            }
            friend poly_NTT operator%(poly_NTT a,poly_NTT b){return a-a/b*b;}
        public:
            inline modint&operator[](uint n){return V[n];};
            poly_NTT&operator+=(poly_NTT b)
            {
                if(size()<b.size())chg_siz(b.size());
                for(uint i=0;i<b.size();i++)V[i]+=b[i];
                cut_zero();return*this;
            }
            inline poly_NTT&operator+=(modint v)
            {
                if(!size())chg_siz(1);
                V[0]+=v;return*this;
            }
            poly_NTT&operator-=(poly_NTT b)
            {
                if(size()<b.size())chg_siz(b.size());
                for(uint i=0;i<b.size();i++)V[i]-=b[i];
                cut_zero();return*this;
            }
            inline poly_NTT&operator-=(modint v)
            {
                if(!size())chg_siz(1);
                V[0]-=v;return*this;
            }
            poly_NTT&operator*=(poly_NTT b)
            {
                modvec&A=V,&B=b.V;
                DIFDIT s(A.size()+B.size());
                s.dif(A),s.dif(B);
                for(uint i=0;i<s.size();i++)A[i]*=B[i];
                s.dit(A),cut_zero();return*this;
            }
            poly_NTT&operator*=(modint v)
            {
                for(auto&t:V)t*=v;
                return*this;
            }
            poly_NTT&operator/=(poly_NTT b){return*this=*this/b;}
            poly_NTT&operator%=(poly_NTT b){return*this=*this%b;}
            poly_NTT&operator<<=(uint v){return*this=*this<<v;}
            poly_NTT&operator>>=(uint v){return*this=*this>>v;}
    };
    template<const ullt p,const ullt g>
    class poly_eval
    {
        public:
            typedef ConstMod::mod_ullt<p>modint;
            typedef std::vector<modint>modvec;
            typedef poly_NTT<p,g>poly;
        private:
            std::vector<poly>G,User;modvec X;
            voi mult_eval_dfs1(uint u,uint l,uint r)
            {
                if(l+1==r){G[u].push(1),G[u].push(-X[l]);return;}
                uint mid=(l+r)/2;mult_eval_dfs1(u<<1,l,mid),mult_eval_dfs1(u<<1|1,mid,r),G[u]=G[u<<1]*G[u<<1|1];
            }
            voi mult_eval_dfs2(uint u,uint l,uint r)
            {
                User.back().chg_siz(r-l);
                if(l+1==r){X[l]=User.back().val(0);return;}
                uint mid=(l+r)/2;
                User.push_back(sub_mul(User.back(),G[u<<1|1])),mult_eval_dfs2(u<<1,l,mid);
                User.back()=sub_mul(User[User.size()-2],G[u<<1]),mult_eval_dfs2(u<<1|1,mid,r);
                User.pop_back();
            }
        public:
            voi operator()(poly P,modvec&X)
            {
                if(X.empty())return;
                G.resize(X.size()<<2),User.clear(),this->X=X;
                mult_eval_dfs1(1,0,X.size());
                User.push_back(sub_mul(P,G[1].inv(std::max<uint>(P.size(),X.size())+1)));
                mult_eval_dfs2(1,0,X.size());
                G.clear(),User.clear(),X=this->X,this->X.clear();
            }
    };
    template<const ullt p,const ullt g>
    class poly_inter
    {
        public:
            typedef ConstMod::mod_ullt<p>modint;
            typedef std::vector<modint>modvec;
            typedef poly_NTT<p,g>poly;
            typedef poly_eval<p,g>eval;
        private:
            std::vector<poly>Lim,F,G;modvec X,H;
            voi dfs(uint l,uint r)
            {
                if(l+1==r)
                {
                    F.push_back(poly()),F.back().push(H[l]),G.push_back(poly()),G.back().push(-X[l]),G.back().push(1);return;
                }
                uint mid=(l+r)>>1;dfs(l,mid),dfs(mid,r);
                F[F.size()-2]=F[F.size()-2]*G.back()+F.back()*G[G.size()-2],F.pop_back(),G[G.size()-2]*=G.back(),G.pop_back();
            }
        public:
            poly operator()(modvec X,modvec Y)
            {
                uint n=std::min(X.size(),Y.size());if(!n)return poly();
                X.resize(n),Y.resize(n),this->X=X;poly P;Lim.clear();
                for(uint i=0;i<n;i++)
                {
                    P.bzr(),P.push(-X[i]),P.push(1);
                    uint w=lowbit(i+1);while(w>>=1)P*=Lim.back(),Lim.pop_back();
                    Lim.push_back(P);
                }
                P=Lim.back(),Lim.pop_back();while(Lim.size())P*=Lim.back(),Lim.pop_back();
                eval()(P.diff(),X),H.resize(n);for(uint i=0;i<n;i++)H[i]=Y[i]/X[i];
                F.clear(),G.clear(),dfs(0,n);
                poly ans=F.back();F.clear(),G.clear(),this->X.clear(),H.clear();return ans;
            }
    };
    template<const ullt p,const ullt g>
    class poly_cpd
    {
        public:
            typedef ConstMod::mod_ullt<p>modint;
            typedef std::vector<modint>modvec;
            typedef poly_NTT<p,g>poly;
            modvec Turn(std::vector<llt>QAQ)
            {
                modvec ans;
                for(uint i=0;i<QAQ.size();i++)ans.push_back((QAQ[i]%(llt)p+p)%p);
                return ans;
            }
            modint point_eval(poly P,modint x)
            {
                modint ans;
                for(uint i=P.deg();~i;i--)ans=ans*x+P[i];
                return ans;
            }
            poly z_npow(poly P,uint n)
            {
                if(P.empty())return P;
                poly ans(P.deg()*n+1);
                for(uint i=0;i<P.size();i++)ans[i*n]+=P[i];
                return ans;
            }
            poly z_npow(poly P,uint n,uint prec)
            {
                poly ans(prec);
                for(uint i=0;i<P.size()&&i*n<prec;i++)ans[i*n]+=P[i];
                return ans;
            }
            poly z_mul_k(poly P,modint k)
            {
                modint t(1);
                for(uint i=0;i<P.size();i++)P[i]*=t,t*=k;
                return P;
            }
            poly z_add_v(poly P,modint v)
            {
                uint n=P.size();if(!n)return P;
                modvec A(n),B(n);
                A[0]=1;for(uint i=1;i<n;i++)A[i]=A[i-1]*i;
                B[n-1]=A[n-1].inv();for(uint i=n-1;i;i--)B[i-1]=B[i]*i;
                poly User(n);modint w(1);
                for(uint i=0;i<n;i++)P[i]*=A[i],User[i]=w*B[i],w*=v;
                P=sub_mul(P,User),P.chg_siz(n);
                for(uint i=0;i<n;i++)P[i]*=B[i];
                return P;
            }
            poly chg_siz(poly P,uint siz){P.chg_siz(siz);return P;}
            poly PolyaInv(poly P,uint prec){return(modint(1)-P).inv(prec);}
            poly PolyaExp(poly P,uint prec)
            {
                modvec inv(prec);
                inv[1]=1;for(uint i=2;i<prec;i++)inv[i]=(p/i)*-inv[p%i];
                poly ans(prec);
                for(uint i=1;i<prec;i++)for(uint j=1;i*j<prec&&j<P.size();j++)ans[i*j]+=P[j]*inv[i];
                return ans.exp(prec);
            }
            poly PolyaInv(poly P){return PolyaInv(P,P.size());}
            poly PolyaExp(poly P){return PolyaExp(P,P.size());}
            voi println(poly P,uint n)
            {
                for(uint i=0;i<n;i++){
                    if(i)putchar(' ');
                    P.val(i).print();
                }
                putchar('\n');
            }
            voi println(poly P){println(P,P.size());}
    };
    template<const ullt p,const ullt g>
    class poly_nums
    {
        public:
            typedef ConstMod::mod_ullt<p>modint;
            typedef std::vector<modint>modvec;
            typedef poly_NTT<p,g>poly;
            typedef poly_cpd<p,g>cpd;
            modvec PowSum(uint n,uint m)
            {
                modvec P(n+2),Q(n+2);
                P[0]=1;for(uint i=1;i<=n+1;i++)P[i]=P[i-1]*i;
                Q[n+1]=P[n+1].inv();for(uint i=n+1;i;i--)Q[i-1]=Q[i]*i;
                poly A(n+1);for(uint i=0;i<=n;i++)A[i]=Q[i+1];
                A=A.inv();
                poly B(n+1);modint v(1);for(uint i=0;i<=n;i++)B[i]=v*Q[i],v*=m;
                B=(B*A-A)>>1;B.chg_siz(n);
                for(uint i=0;i<n;i++)B[i]*=P[i];
                return B.GET();
            }
            modvec S1R(uint n)
            {
                if(!n)return modvec({modint(1)});
                if(n&1)return(S1R(n-1)*poly(modvec({n-1,1}))).GET();
                poly P=S1R(n>>1);P*=cpd().z_add_v(P,n>>1);return P.GET();
            }
            modvec S1C(uint n,uint prec)
            {
                if(n>=prec)return modvec(prec);
                modvec P(prec+1),Q(prec+1);
                P[0]=1;for(uint i=1;i<=prec;i++)P[i]=P[i-1]*i;
                Q[prec]=P[prec].inv();for(uint i=prec;i;i--)Q[i-1]=Q[i]*i;
                poly ans;
                for(uint i=1;i<=prec-n;i++)ans.push(Q[i]*P[i-1]);
                ans=(ans.ln(prec-n)*modint(n)).exp(prec-n)<<n;
                modint v=1;
                for(uint i=1;i<=n;i++)v*=i;
                ans=ans*v.inv();
                for(uint i=n;i<prec;i++)ans[i]*=P[i];
                return ans.GET();
            }
            modvec S2R(uint n)
            {
                modvec P(n+1),Q(n+1);
                P[0]=1;for(uint i=1;i<=n;i++)P[i]=P[i-1]*i;
                Q[n]=P[n].inv();for(uint i=n;i;i--)Q[i-1]=Q[i]*i;
                poly A(n+1),B(n+1);
                A[0]=!n;if(n)A[1]=1;
                std::vector<uint>Prime;
                std::vector<bol>Gone(n+1);
                for(uint i=2;i<=n;i++)
                {
                    if(!Gone[i]){Prime.push_back(i);modint v=modint(i)._power(n);for(ullt j=i;j<=n;j*=i)A[j]=v*A[j/i],Gone[j]=true;}
                    for(auto w:Prime)if(i*w<=n&&i%w){for(ullt j=w;i*j<=n;j*=w)A[i*j]=A[i]*A[j],Gone[i*j]=true;}else break;
                }
                for(uint i=0;i<=n;i++)A[i]*=Q[i],B[i]=(i&1?p-1:1)*Q[i];
                A*=B,A.chg_deg(n);
                return A.GET();
            }
            modvec S2C(uint n,uint prec)
            {
                if(n>=prec)return modvec(prec);
                modvec P(prec+1),Q(prec+1);
                P[0]=1;for(uint i=1;i<=prec;i++)P[i]=P[i-1]*i;
                Q[prec]=P[prec].inv();for(uint i=prec;i;i--)Q[i-1]=Q[i]*i;
                poly ans=PowSum(prec-n,n+1);
                ans[0]=0;for(uint i=1;i<prec-n;i++)ans[i]*=Q[i]*P[i-1];
                ans=ans.exp(prec-n)<<n;
                return ans.GET();
            }
    };
}
namespace FWT_MODINT
{
    template<const ullt p>
    class FWT_Mod
    {
        public:
            typedef ConstMod::mod_ullt<p>modint;
            typedef std::vector<modint>modvec;
        private:
            uint n;
        public:
            FWT_Mod():n(0){}
            voi bzr(uint len){n=1;while(n<len)n<<=1;}
            uint size(){return n;}
            voi OR(modvec&x,bol op)
            {
                if(x.size()<n)x.resize(n);
                for(uint i=1;i<n;i<<=1)for(uint j=0;j<n;j+=i<<1)for(uint k=0;k<i;k++)
                    op?x[i+j+k]-=x[j+k]:x[i+j+k]+=x[j+k];
            }
            voi AND(modvec&x,bol op)
            {
                if(x.size()<n)x.resize(n);
                for(uint i=1;i<n;i<<=1)for(uint j=0;j<n;j+=i<<1)for(uint k=0;k<i;k++)
                    op?x[j+k]-=x[i+j+k]:x[j+k]+=x[i+j+k];
            }
            voi XOR(modvec&x,bol op)
            {
                if(x.size()<n)x.resize(n);
                for(uint i=1;i<n;i<<=1)for(uint j=0;j<n;j+=i<<1)for(uint k=0;k<i;k++)
                {
                    modint u=x[j+k],t=x[i+j+k];x[j+k]=u+t,x[i+j+k]=u-t;
                }
                if(op){modint v=modint(n).inv();for(uint i=0;i<n;i++)x[i]*=v;}
            }
    };
}
const ullt Mod=998244353,g=3;
typedef ConstMod::mod_ullt<Mod>modint;
typedef std::vector<modint>modvec;
typedef NTT_POLY::poly_NTT<Mod,g>poly;
typedef NTT_POLY::poly_eval<Mod,g>eval;
typedef NTT_POLY::poly_inter<Mod,g>inter;
typedef NTT_POLY::poly_cpd<Mod,g>cpd;
typedef NTT_POLY::poly_nums<Mod,g>nums;
typedef FWT_MODINT::FWT_Mod<Mod>FWT;
posted @   OIer_Albedo  阅读(65)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 记一次.NET内存居高不下排查解决与启示
点击右上角即可分享
微信分享提示