suxxsfe

一言(ヒトコト)

打印4

高斯消元

需要求逆元:

inline ModInt det(int n,ModInt (*a)[N]){
	ModInt ans;ans=1;
	for(int i=1;i<=n;i++){
		if(!a[i][i].x){
			ans=0-ans;
			for(int k=i+1;k<=n;k++)if(a[k][i].x){std::swap(a[i],a[k]);goto CONTINUE;}
			return {0};
		}
	CONTINUE:
		ans*=a[i][i];
		for(int k=i+1;k<=n;k++)if(a[k][i].x){
			ModInt o=a[k][i]/a[i][i];
			for(int j=i;j<=n;j++) a[k][j]-=a[i][j]*o;
		}
	}
	return ans;
}

不需要逆元:

inline ModInt det(){
	ModInt ans;ans=1;
	for(int i=1;i<=n;i++){
		for(int j=i+1;j<=n;j++){
			while(a[j][i]){
				long long k=a[i][i]/a[j][i];
				for(int h=1;h<=n;h++) a[i][h]-=k*a[j][h];
				std::swap(a[i],a[j]);
				ans=-ans;
			}
		}
	}
	for(int i=1;i<=n;i++) ans*=a[i][i];
	return ans;
}

矩阵求逆(高斯消元法)

inline int work(){
	for(int i=1;i<=n;i++){
		if(!a[i][i]){
			for(int k=i+1;k<=n;k++)if(a[k][i]){
				std::swap(a[k],a[i]);goto CONTINUE;
			}
			return 0;
		}
CONTINUE:
		long long inv=power(a[i][i],MOD-2);
		for(int k=i+1;k<=n;k++)if(a[k][i]){
			long long o=a[k][i]*inv%MOD;
			for(int j=i;j<=n<<1;j++) a[k][j]-=a[i][j]*o%MOD,a[k][j]=(a[k][j]+MOD)%MOD;
		}
	}
	for(int i=n;i;i--){
		if(!a[i][i]){
			for(int k=i-1;k;k--)if(a[k][i]){
				std::swap(a[k],a[i]);break;
			}
		}
		long long inv=power(a[i][i],MOD-2);
		for(int k=1;k<i;k++)if(a[k][i]){
			long long o=a[k][i]*inv%MOD;
			for(int j=i;j<=n<<1;j++) a[k][j]-=a[i][j]*o%MOD,a[k][j]=(a[k][j]+MOD)%MOD;
		}
		for(int j=i;j<=n<<1;j++) a[i][j]=a[i][j]*inv%MOD;
	}
	return 1;
}

快速乘 和 minner-rabbin 和 Pollard-Rho

inline unsigned long long Rand(){
	return (unsigned long long)rand()*RAND_MAX*RAND_MAX+(unsigned long long)rand()*RAND_MAX+
	(unsigned long long)rand()*RAND_MAX*RAND_MAX*RAND_MAX+rand();
}
inline long long mul(long long x,long long y,long long mod){
	return (x*y-(long long)((long double)x/mod*y)*mod+mod)%mod;
}
inline long long power(long long a,long long b,long long mod){
	long long ans=1;
	while(b){
		if(b&1) ans=mul(ans,a,mod);
		a=mul(a,a,mod);b>>=1;
	}
	return ans;
}
inline int check(long long x,int p){
	long long d=x-1,r=0;
	while(!(d&1)) d>>=1,r++;
	long long pd=power(p,d,x);
	if(pd==1) return 1;
	while(r--){
		if(pd==x-1) return 1;
		pd=mul(pd,pd,x);
	}
	return 0;
}
const int P[]={2,3,5,7,11,13,17,37};
inline int isPrime(long long x){
	if(x<2) return 0;
	for(int i=0;i<8;i++){
		if(x==P[i]) return 1;
		if(!(x%P[i])) return 0;
		if(!check(x,P[i])) return 0;
	}
	return 1;
}
inline long long getGcd(long long a,long long b){return b?getGcd(b,a%b):a;}
long long divide(long long x){
	if(isPrime(x)) return x;
	long long T;
	int k=log2(x),o=k;
	for(;;){
		T=Rand()%19260917+1;
		long long v0=Rand()%(x-1)+1,v=(mul(v0,v0,x)+T)%x,sum=1;
		while(v0^v){
			sum=mul(sum,std::abs(v-v0),x);
			if(!sum) break;
			if(!o--){
				long long d=getGcd(sum,x);
				if(d>1&&d<x) return std::max(divide(d),divide(x/d));
				o=k;
			}
			v=(mul(v,v,x)+T)%x;v=(mul(v,v,x)+T)%x;v0=(mul(v0,v0,x)+T)%x;
		}
	}
}

ntt

常用素数:
P = 1004535809  ====>  pr = 3
P = 998244353  =====>  pr = 3

 

\(n\) 存的是项数而不是次数

inline int init(int n){
	int max=1;while(max<n) max<<=1;
	for(int i=0;i<max;i++) rev[i]=rev[i>>1]>>1,rev[i]|=(i&1)?(max>>1):0;
	return max;
}
inline void ntt(int n,long long *a,int type){
	for(int i=0;i<n;i++)if(rev[i]<i) std::swap(a[i],a[rev[i]]);
	for(int h=1;h<n;h<<=1){
		long long gn=power(G,(mod-1)/(h<<1)),g,o;
		if(!type) gn=power(gn,mod-2);
		for(int i=0,j;i<n;i+=h<<1){
			for(g=1,j=i;j<i+h;j++,g=g*gn%mod){
				o=g*a[j+h]%mod;
				a[j+h]=(a[j]-o+mod)%mod;a[j]=(a[j]+o)%mod;
			}
		}
	}
	if(!type){
		long long inv=power(n,mod-2);
		for(int i=0;i<n;i++) a[i]=a[i]*inv%mod;
	}
}

多项式乘法逆

int tmp[N];
inline void inv(int n,int *f,int *g){
	if(n==1) return g[0]=power(f[0],mod-2),void();
	inv((n+1)>>1,f,g);
	int max=init(n+n);
	std::memcpy(tmp,f,n*sizeof(f[0]));
	for(reg int i=n;i<max;i++) tmp[i]=g[i]=0;
	ntt(max,tmp,1);ntt(max,g,1);
	for(reg int i=0;i<max;i++) g[i]=(2-(long long)tmp[i]*g[i]%mod+mod)%mod*g[i]%mod;
	ntt(max,g,0);
	for(reg int i=n;i<max;i++) g[i]=0;
}

分治 fft

void work(int l,int r){
	if(l==r) return f[l]=(l?f[l]:(ModInt){1}),void();
	int mid=(l+r)>>1;
	work(l,mid);
	static ModInt f[N*4],g[N*4];
	int len=init((r-l+1));
	std::memcpy(f,::f+l,(mid-l+1)*sizeof f[0]);std::memset(f+mid-l+1,0,(len-mid+l-1)*sizeof f[0]);
	std::memcpy(g,::g,(r-l+1)*sizeof g[0]);std::memset(g+r-l+1,0,(len-r+l-1)*sizeof g[0]);
	ntt(len,f,1);ntt(len,g,1);
	for(int i=0;i<len;i++) f[i]*=g[i];
	ntt(len,f,0);
	for(int i=mid+1;i<=r;i++) ::f[i]+=f[i-l];
	work(mid+1,r);
}

fwt

inline void Or(int n,long long *f){for(int h=1;h<n;h<<=1)for(int i=0;i<n;i+=h<<1)for(int j=0;j<h;j++) f[i+j+h]+=f[i+j];}
inline void IOr(int n,long long *f){for(int h=1;h<n;h<<=1)for(int i=0;i<n;i+=h<<1)for(int j=0;j<h;j++) f[i+j+h]-=f[i+j];}
inline void And(int n,long long *f){for(int h=1;h<n;h<<=1)for(int i=0;i<n;i+=h<<1)for(int j=0;j<h;j++) f[i+j]+=f[i+j+h];}
inline void IAnd(int n,long long *f){for(int h=1;h<n;h<<=1)for(int i=0;i<n;i+=h<<1)for(int j=0;j<h;j++) f[i+j]-=f[i+j+h];}
inline void Xor(int n,long long *f){
	for(int h=1;h<n;h<<=1)for(int i=0;i<n;i+=h<<1)for(int j=0;j<h;j++)
		f[i+j]+=f[i+j+h],f[i+j+h]=f[i+j]-f[i+j+h]-f[i+j+h];
}
inline void IXor(int n,long long *f){
	for(int h=1;h<n;h<<=1)for(int i=0;i<n;i+=h<<1)for(int j=0;j<h;j++)
		f[i+j]+=f[i+j+h],f[i+j+h]=f[i+j]-f[i+j+h]-f[i+j+h],f[i+j]*=inv2,f[i+j+h]*=inv2;
}

lu div

inline void luDiv(int n,ModInt (*l)[N],ModInt (*u)[N],ModInt (*a)[N]){
	for(int i=1;i<=n;i++){
		for(int j=i;j<=n;j++){
			u[i][j]=a[i][j];
			for(int k=1;k<i;k++) u[i][j]-=l[i][k]*u[k][j];
			l[j][i]=a[j][i];
			for(int k=1;k<i;k++) l[j][i]-=l[j][k]*u[k][i];
			l[j][i]/=u[i][i];
		}
		l[i][i]=1;
	}
}

lgv

matrix-tree best



(ex)bsgs

std::map<int,int>map;
inline int BSGS(int a,int n,int p,int ad){
	int m=std::ceil(std::sqrt(p));
	map.clear();
	for(int i=0,s=n;i<m;i++,s=(long long)s*a%p) map[s]=i;
	for(int i=0,tmp=power(a,m,p),s=ad;i<=m;i++,s=(long long)s*tmp%p)
		if(map.find(s)!=map.end()&&(long long)i*m>map[s]) return (long long)i*m-map[s];
	return -1;
}
inline int exBSGS(int a,int n,int p){
	a%=p;n%=p;
	if(n==1||p==1) return 0;
	int cnt=0,d,ad=1;
	while((d=gcd(a,p))^1){
		if(n%d) return -1;
		cnt++;n/=d;p/=d;
		ad=((long long)ad*a/d)%p;
		if(ad==n) return cnt;
	}
	long long ans=BSGS(a,n,p,ad);
	return (~ans)?(ans+cnt):-1;
}

exgcd

long long exgcd(long long a,long long b,long long &x,long long &y){
	if(!b) return x=1,y=0,a;
	long long gcd=exgcd(b,a%b,x,y);
	long long tmp=x;x=y;
	y=tmp-a/b*y;
	return gcd;
}

(ex)crt

M=1;
for(reg int i=1;i<=n;i++) M*=m[i];
long long tmp;
for(reg int i=1;i<=n;i++) exgcd(M/m[i],m[i],t[i],tmp);
long long ans=0;
for(reg int i=1;i<=n;i++) ans+=a[i]*t[i]%M*(M/m[i])%M+M,ans%=M;

inline long long excrt(){
	long long M=m[1],ans=a[1],x,y,tmp,gcd;
	for(reg int i=2;i<=n;i++){
		tmp=((a[i]-ans)%m[i]+m[i])%m[i];
		gcd=exgcd(M,m[i],x,y);
		tmp=mul(x,tmp/gcd,m[i]);
		ans+=M*tmp;
		M*=m[i]/gcd;
		ans=(ans+M)%M;
	}
	return ans;
}

线性基

inline void insert(long long x){
	for(reg int i=50;~i;i--)if(x&(1ll<<i)){
		if(!a[i]){a[i]=x;return;}
		else x^=a[i];
	}
}

自适应辛普森

inline double simpson(double l,double r){
	return (r-l)*(calc(l)+4*calc((l+r)/2)+calc(r))/6;
}
double asr(double l,double r,double eps,double ans){
	double mid=(l+r)/2;
	double fl=simpson(l,mid),fr=simpson(mid,r);
	if(std::fabs(fl+fr-ans)<=15*eps) return fl+fr+(fl+fr-ans)/15;
	return asr(l,mid,eps/2,fl)+asr(mid,r,eps/2,fr);
}

lib

struct Vector{
	double x,y;
	inline Vector(){x=y=0;}
	inline Vector(double _x,double _y){x=_x;y=_y;}
	inline double len(){return __builtin_sqrt(x*x+y*y);}
	inline double len2(){return x*x+y*y;}
	inline void operator += (const Vector &a){x+=a.x;y+=a.y;}
	inline void operator -= (const Vector &a){x-=a.x;y-=a.y;}
	inline void operator *= (const double &a){x*=a;y*=a;}
	inline void operator /= (const double &a){x/=a;y/=a;}
	inline Vector operator + (const Vector &a)const{return {x+a.x,y+a.y};}
	inline Vector operator - (const Vector &a)const{return {x-a.x,y-a.y};}
	inline Vector operator * (const double &a)const{return {x*a,y*a};}
	inline Vector operator / (const double &a)const{return {x/a,y/a};}
	inline double operator * (const Vector &a)const{return x*a.x+y*a.y;}
	inline double operator ^ (const Vector &a)const{return x*a.y-y*a.x;}
};
struct Line{
	Vector way,o;
	inline Line(){}
	inline Line(double a,double b,double c){//ax+by+c=0
		if(std::abs(a)>=eps) o=Vector(-c/a,0);
		else o=Vector(0,-c/b);
		way=Vector(b,-a);
	}
	inline Line(const Vector &a,const Vector &b){o=a;way=b-a;}
};
inline Vector getIntersection(const Line &a,const Line &b){
	double x=(b.way^(a.o-b.o))/(a.way^b.way);
	return a.o+a.way*x;
}

二维凸包

inline int graham(int n,Vector *p,Vector *stack){
	for(int i=2;i<=n;i++) p[i].ang=atan2(p[i].y-p[1].y,p[i].x-p[1].x);
	std::sort(p+2,p+1+n);
	stack[1]=p[1];int top=1;
	for(int i=2;i<=n;i++){
		while(top>1&&cross(p[i]-stack[top],stack[top]-stack[top-1])<=eps) top--;
		stack[++top]=p[i];
	}
	stack[++top]=p[1];
	return top;
}

半平面交

int left,right;
Line que[N];
inline int halfPlane(int n,Line *a,Vector *p){
	std::sort(a+1,a+1+n,cmp);
	left=right=0;que[0]=a[1];
	for(int i=2;i<=n;i++){
		while(left<right&&onRight(a[i],p[right])) right--;
		while(left<right&&onRight(a[i],p[left+1])) left++;
		que[++right]=a[i];
		if(abs(cross(que[right].way,que[right-1].way))<=eps){//平行
			if(onRight(que[right],que[right-1].p)&&dot(que[right].way,que[right-1].way)<=-eps) return 0;
			right--;
			if(!onRight(que[right],a[i].p)) que[right]=a[i];
		}
		if(left<right) p[right]=intersect(que[right],que[right-1]);
	}
	while(left<right&&onRight(que[left],p[right])) right--;
	if(right-left<=1) return 0;
	p[left]=intersect(que[left],que[right]);
	return 1;
}

旋转卡壳

inline int nex(int i){return i==n?1:(i+1);}
int main(){
	if(n<=3) return printf("%lld\n",(q[2]-q[1]).len()),0;
	long long ans=0;
	for(int i=1,j=3;i<n;i++){
		while(abs((q[j]-q[i])^(q[j]-q[i+1]))<=abs((q[nex(j)]-q[i])^(q[nex(j)]-q[i+1]))) j=nex(j);
		ans=std::max(ans,std::max((q[j]-q[i]).len(),(q[j]-q[i+1]).len()));
	}
	printf("%lld\n",ans);
	return 0;
}

3-d 凸包

struct Plane{
	Vector a,b,c;//a->b->c counterclockwise
	int x,y,z;
	inline Plane(){}
	inline Plane(const Vector &_a,const Vector &_b,const Vector &_c,int _x=0,int _y=0,int _z=0){a=_a;b=_b;c=_c;x=_x;y=_y;z=_z;}
	inline Vector normal()const{return (c-b)^(a-b);}
	inline double area()const{return ((c-b)^(a-b)).len()/2;}
};
inline int isAbove(const Plane &p,const Vector &v){
	return sign(p.normal()*(v-p.a))==1;
}
inline int isCollinear(const Vector &a,const Vector &b,const Vector &c){
	return sign(((b-a)^(c-a)).len2())==0;
}
inline int isCoplanar(const Vector &a,const Vector &b,const Vector &c,const Vector &d){
	return sign(Plane(a,b,c).normal()*(d-a))==0;
}
inline int work(int n,Vector *a,Plane *p){
	if(n<3) return 0;
	int s[4];
	s[0]=1;s[1]=2;s[2]=3;s[3]=4;
	while(s[2]<=n&&isCollinear(a[s[0]],a[s[1]],a[s[2]])) s[2]++;
	if(s[2]>n) return 0;
	while(s[3]<=n&&isCoplanar(a[s[0]],a[s[1]],a[s[2]],a[s[3]])) s[3]++;
	if(s[3]>n) return 0;
	if(!isAbove(Plane(a[s[0]],a[s[1]],a[s[2]]),a[s[3]])) std::swap(s[2],s[3]);
	int tot=0;
	p[++tot]=Plane(a[s[0]],a[s[2]],a[s[1]],s[0],s[2],s[1]);
	p[++tot]=Plane(a[s[0]],a[s[1]],a[s[3]],s[0],s[1],s[3]);
	p[++tot]=Plane(a[s[0]],a[s[3]],a[s[2]],s[0],s[3],s[2]);
	p[++tot]=Plane(a[s[1]],a[s[2]],a[s[3]],s[1],s[2],s[3]);
	static Plane u[N*2],v[N*2];
	static int tag[N][N];
	for(int i=4;i<=n;i++){
		int _u=0,_v=0;
		for(int j=1;j<=tot;j++){
			if(!isAbove(p[j],a[i])) u[++_u]=p[j];
			else{
				v[++_v]=p[j];
				tag[p[j].x][p[j].y]=tag[p[j].y][p[j].z]=tag[p[j].z][p[j].x]=i;
			}
		}
		tot=0;
		for(int j=1;j<=_v;j++){
			if(tag[v[j].y][v[j].x]!=i) p[++tot]=Plane(v[j].a,v[j].b,a[i],v[j].x,v[j].y,i);
			if(tag[v[j].z][v[j].y]!=i) p[++tot]=Plane(v[j].b,v[j].c,a[i],v[j].y,v[j].z,i);
			if(tag[v[j].x][v[j].z]!=i) p[++tot]=Plane(v[j].c,v[j].a,a[i],v[j].z,v[j].x,i);
		}
		for(int j=1;j<=_u;j++) p[++tot]=u[j];
	}
	return tot;
}

kmp

fail[1]=0;
for(int j,i=2;i<=m;i++){
	j=fail[i-1];
	while(t[j+1]!=t[i]&&j) j=fail[j];
	fail[i]=j+(t[j+1]==t[i]);
}
for(int j=0,i=1;i<=n;i++){
	while(s[i]!=t[j+1]&&j) j=fail[j];
	if(s[i]==t[j+1]) j++;
	if(j==m) printf("%d\n",i-m+1),j=fail[j];
}

manacher

for(reg int i=1;i<=n;i++) s[i+i]=in[i],s[i+i+1]=2;
n+=n+1;
int pos=0,max=0;
s[0]=0;s[1]=2;s[n+1]=1;
int ans=0;
for(int i=1;i<=n;i++){
	if(pos+max-1<i) len[i]=1;
	else len[i]=std::min(len[pos+pos-i],pos+max-i);
	while(s[i+len[i]]==s[i-len[i]]) len[i]++;
	if(i+len[i]-1>=pos+max-1) pos=i,max=len[i];
	ans=std::max(ans,len[i]-1);
}

AC 自动机

struct Node{
	Node *tr[26],*fail;
	int cnt,in;
}dizhi[N],*root=dizhi,*which[N],*cur=dizhi;
inline void insert(char *s,int id){
	Node *tree=root;
	for(int num,i=1;s[i];i++){
		num=s[i]-'a';
		if(!tree->tr[num]) tree->tr[num]==++cur;
		tree=tree->tr[num];
	}
	which[id]=tree;
}
int left,right;
Node *que[N];
inline void build(){
	left=0;right=-1;
	root->fail=root;
	for(int i=0;i<26;i++){
		if(root->tr[i]) root->tr[i]->fail=root,que[++right]=root->tr[i];
		else root->tr[i]=root;
	}
	Node *u;
	while(left<=right){
		u=que[left++];
		for(int i=0;i<26;i++){
			if(u->tr[i]){
				u->tr[i]->fail=u->fail->tr[i];
				que[++right]=u->tr[i];u->fail->tr[i]->in++;
			}
			else u->tr[i]=u->fail->tr[i];
		}
	}
}

SAM

struct Node{
	Node *son[26];
	int len,cnt;
	Node *link;
}dizhi[N*2],*root=dizhi,*last=root,*cur=dizhi;
inline void add(int c){
	Node *p=last,*now=++cur;
	now->len=p->len+1;now->cnt=1;
	for(;p&&!p->son[c];p=p->link) p->son[c]=now;
	if(!p) now->link=root;
	else{
		Node *q=p->son[c];
		if(q->len==p->len+1) now->link=q;
		else{
			Node *clone=++cur;*clone=*q;
			clone->len=p->len+1;clone->cnt=0;
			q->link=now->link=clone;
			for(;p&&p->son[c]==q;p=p->link) p->son[c]=clone;
		}
	}
	last=now;
}

PAM

struct Node{
	Node *son[26],*fail;
	int len,cnt;
}dizhi[N],*root0=&dizhi[0],*root1=&dizhi[1],*last,*cur=dizhi;
inline void init(){
	last=root1;
	root0->fail=root1;root1->fail=root0;
	root1->len=-1;
	cur++;
}
char s[N];
inline int cnt(Node *u){
	if(u==root0||u==root1) return 0;
	if(u->cnt) return u->cnt;
	return u->cnt=1+cnt(u->fail);
}
inline int insert(int i){
	while(s[i-last->len-1]^s[i]) last=last->fail;
	if(!last->son[s[i]-'a']){
		Node *u=++cur;
		u->len=last->len+2;
		reg Node *j=last->fail;
		while(s[i-j->len-1]^s[i]) j=j->fail;
		u->fail=j->son[s[i]-'a'];
		if(!u->fail) u->fail=root0;
		last->son[s[i]-'a']=u;
	}
	last=last->son[s[i]-'a'];
	return cnt(last);
}

斜率优化

for(reg int i=1;i<=n;i++){
	while(left<right&&
	get_y(q[left+1])-get_y(q[left])<=b[i].l*(get_x(q[left+1])-get_x(q[left]))) left++;
	int j=q[left];
	f[i]=f[j]+b[j+1].w*k;
	while(left<right&&(get_y(q[right])-get_y(q[right-1]))*(get_x(i)-get_x(q[right]))
	>=(get_y(i)-get_y(q[right]))*(get_x(q[right])-get_x(q[right-1]))) right--;
	q[++right]=i;
}
posted @ 2023-08-29 21:49  suxxsfe  阅读(24)  评论(0编辑  收藏  举报