My All Math

哦背背:

atan2(△y,△x) :极角

acos(-1):π

cos()、sin():。

__builtin_popcount(x)、__builtin_popcountll(x):1 的个数

两直线交点

设两直线方程分别为:
\(l_1=P+t\)v
\(l_2=Q+t\)w

\(t=[(P−Q)×\)w\(]/(\)w\(×\)v\()\)

三点定圆

void ding(xxx o1,xxx o2,xxx o3)
{
	double 
	a1=o2.x-o1.x,a2=o3.x-o1.x,
	b1=o2.y-o1.y,b2=o3.y-o1.y,
	c1=(o2.x*o2.x-o1.x*o1.x+o2.y*o2.y-o1.y*o1.y)/2,
	c2=(o3.x*o3.x-o1.x*o1.x+o3.y*o3.y-o1.y*o1.y)/2;
	o={(b2*c1-b1*c2)/(b2*a1-b1*a2),(a2*c1-a1*c2)/(a2*b1-a1*b2)};
	r=dis(o,o1)+eps;
}

叉积求面积

\(S_{△}=½\)a\(×\)b

卡特兰数(找规律用)

切比雪夫距离与曼哈顿距离

曼哈顿 \((x,y) = (x+y,x-y)\) 的切比雪夫
切比雪夫 \((x,y) = ((x+y)/2,(x-y)/2)\) 的曼哈顿

累加公式

平方:\(n(n+1)(2n+1)/6\)
立方:\([n(n+1)/2]^2\)
证明是数形结合旋转三角/

插板法

把 n 个苹果分给 m 个人:
\(C_{m+n-1}^{n-1}\)


不仅详细地说明了算法流程,并且证明也是忽略了,而且一些必要的解释也是很好背了。

log

log(a):以 e 为底
log2(a):以 2 为底
log(a)/log(b):以 b 为底

1. 旋转坐标系

公式

  • 绕原点旋转‌:
    逆时针旋转θ角度时:
    \(x′=xcos⁡θ−ysin⁡θ\)
    \(y′=xsin⁡θ+ycos⁡θ\)

逆时针旋转 θ 度矩阵:

cos(θ) sin(θ)
-sin(θ) cos(θ)
  • 绕任意点 \((a,b)\) 旋转‌:
    分三步实现:平移坐标系使旋转中心到原点→应用绕原点旋转公式→反向平移。公式为:
    \(x′=(x−a)cos⁡θ−(y−b)sin⁡θ+a\)
    \(y′=(x−a)sin⁡θ+(y−b)cos⁡θ+b\)

应用

维护凸包时 \(y\) 最小的点一定会被选上,那么将坐标系旋转一圈记录即可。

随机旋转角度并按 \(x\) 排序后,暴力取每个点与周围 \(5\) 个点寻找。
如果过不了也只能调排序方式、随机次数、取点个数了。

2. 二维凸包

先找 \(y\) 最小的那个点,用 atan2(△y,△x) 极角排序其余点,然后维护栈,如果栈顶两个点的直线与当前点与栈顶点的直线叉积 \(<0\),那么弹栈,最后再插入一下最开始那个点就是凸包了。

\(a×b=x_a×y_b-y_a×x_b\)

\(a×b<0\) 则 b 是 a 顺时针旋转。
\(a×b>0\) 则 b 是 a 逆时针旋转。

细节:
cmp1 若 y 等则按 x 排。
cmp2 若 val 等则按 y 排。
怎么排无所谓。

3. FWT

运算矩阵:

1 0
1 1

逆矩阵:

1 0
-1 1

运算矩阵:

1 1
0 1

逆矩阵:

1 -1
0 1

运算矩阵:

1 1
1 -1

逆矩阵:

1/2 1/2
1/2 -1/2

矩阵的 \((i,j)\) 表示 \(j\)\(i\) 的贡献。

哦背背,只因你太美!(注意下面的 len 是默认 \(2\) 的整次幂)

void fwt(int op,int *a,int k)
{
	for(int len=2;len<=(n+1);len*=2)
		for(int i=0;i+len-1<=n;i+=len)
			for(int j=i,o0,o1;j<i+len/2;j++)
				o0=a[j],o1=a[j+len/2],
				a[j]=((o0*jz[op][k][0][0]+o1*jz[op][k][0][1])%mo+mo)%mo,
				a[j+len/2]=((o0*jz[op][k][1][0]+o1*jz[op][k][1][1])%mo+mo)%mo;
}

因为要拆位算贡献,所以分成两半,最后类似分治结构。
综上,先枚举区间长度再枚举区间起始点再枚举区间左半,因为右半我是在左边算的。


fwt(k,A,0),fwt(k,B,0);
for(int i=0;i<=n;i++) C[i]=A[i]*B[i]%mo;
fwt(k,C,1);

上面就计算了两个多项式或、与、亦或卷积,可以应用到形式幂级数。

集合幂级数

\[c_k=\sum_{\substack{{i ∩ j=∅}\\{i∪j=k}}} a_i b_j \]

\(i∪j=k\) 可以或卷积求出 c_k。
\(i∩j=∅\) 相当于 \(∣ i ∪ j ∣=∣i∣+∣j∣\)

$ f(i,S)=∑_{T∈S, ∣T∣=i}f(T)$
\(h(i,S)=∑_{j=0}^i f_a(j,S)f_b(i−j,S)\)
\(ans_i=h(∣i∣,i)\)

\(h\) 数组的卷积:

for(int i=0;i<=m;i++)
		for(int k=0;k<=i;k++)
			for(int j=0;j<=n;j++)
				c[i][j]=(c[i][j]+(ll)a[k][j]*b[i-k][j]%mo)%mo;

小识:

int__builtin_popcount(x)
long long__builtin_popcountll(x)

寻址连续好快!上面那三个 for 循环最后枚举 \(j\) 很快!(先枚举 \(j\) 导致 \(a,b\) 寻址更连续 )

4. 数论分块

\(\%\) 拆为下取整除法。
\(l\) 所在块的右端点为 \(k/(k/l)\)
\(l=r+1\)

\(k<i\le n\) 时会剩下一堆,直接算到 \(n\)

5. 多项式乘法

卷积好用
兄弟,好背!

#include<bits/stdc++.h>
using namespace std;
const double pai=acos(-1);
const int QAQ=4e6+7;
int n,m,len=1;
complex<double> f[QAQ],g[QAQ],c[QAQ],cab[QAQ];
void fft(complex<double> *a,int n,int k)
{
	if(n==1) return ;
	for(int i=0;i<n;i++)
		if(i&1) cab[i/2+n/2]=a[i];
		else cab[i/2]=a[i];
	for(int i=0;i<n;i++) a[i]=cab[i];
	complex<double> *x=a,*y=a+n/2;
	fft(x,n/2,k);
	fft(y,n/2,k);
	complex<double> i(1,0),u(cos(2*pai/n),k*sin(2*pai/n));
	for(int t=0;t<n/2;t++) cab[t]=x[t]+i*y[t],cab[t+n/2]=x[t]-i*y[t],i=i*u;
	for(int t=0;t<n;t++) a[t]=cab[t];
}
signed main()
{
	cin>>n>>m;
	while(len<=n+m+2) len*=2;
	for(int i=0;i<=n;i++) cin>>f[i];
	for(int i=0;i<=m;i++) cin>>g[i];
	fft(f,len,1);
	fft(g,len,1);
	for(int i=0;i<len;i++) c[i]=f[i]*g[i];
	fft(c,len,-1);
	for(int i=0;i<=n+m;i++) cout<<(int)(c[i].real()/len+0.5)<<" ";
	return 0;
}

分治 NTT,调用自己之物

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int QAQ=4e5+7,mo=998244353;
int n,g[QAQ],f[QAQ]={1};
int ksm(int x,int k)
{
	int da=1;
	for(;k;k>>=1,x=x*x%mo) if(k&1) da=da*x%mo;
	return da;
}
int cab[QAQ],tmp[QAQ];
void ntt(int a[],int n,int op)
{
	for(int i=0;i<n;i++)
	{
		cab[i]=cab[i/2]/2;
		if(i&1) cab[i]=cab[i]+n/2;
	}
	for(int i=0;i<n;i++) tmp[cab[i]]=a[i];
	for(int i=0;i<n;i++) a[i]=tmp[i];
	for(int k=1;k<n;k<<=1)
	{
		int u=(op==1?3:ksm(3,mo-2));
		u=ksm(u,(mo-1)/(k*2));
		for(int i=0;i<n;i+=k*2)
		{
			int o=1;
			for(int j=0;j<k;j++)
			{
				int x=a[i+j],y=o*a[i+j+k]%mo;
				a[i+j]=(x+y)%mo;
				a[i+j+k]=(x-y+mo)%mo;
				o=o*u%mo;
			}
		}
	}
}

void getntt(int a[],int n,int b[],int m)
{
	int len=1;
	while(len<=n+m) len*=2;
	for(int i=n;i<=len;i++) a[i]=0;
	for(int i=m;i<=len;i++) b[i]=0;
	ntt(a,len,1),ntt(b,len,1);
	for(int i=0;i<len;i++) a[i]=b[i]*a[i]%mo;
	ntt(a,len,-1);
	int ni=ksm(len,mo-2);
	for(int i=0;i<len;i++) a[i]=a[i]*ni%mo;
}
int a[QAQ],b[QAQ];
void cdq(int l,int r)
{
	if(l==r) return ;
	int mid=(l+r)>>1;
	cdq(l,mid);	
	for(int i=l;i<=mid;i++) a[i-l]=f[i];
	for(int i=1;i<=r-l;i++) b[i]=g[i];
	getntt(a,mid-l+1,b,r-l+1);
	for(int i=mid+1;i<=r;i++) f[i]=(f[i]+a[i-l])%mo;
	cdq(mid+1,r);
}
signed main()
{
	cin>>n;
	for(int i=1;i<n;i++) cin>>g[i];
	cdq(0,n-1);
	for(int i=0;i<n;i++) cout<<f[i]<<' ';
	return 0;
}

6. 半平面交

小言

逆转叉积正。
一个直线我们只取它左边。

流程

极角排序所有直线,如果极角相同优先靠左的直线。
存两个队列——交点队列和直线队列,注意交点队列在运算时总是比直线队列短 \(1\)
遍历所有直线,如果两个直线极角一样(差 eps)那么不重复计算,在交点队列弹掉所有在当前直线右边的点。
把当前直线加入直线队列并在交点队列里加上其与直线队列上一个直线的交点。
最后再用直线队列的尾消一下交点队列的头
再拿新直线队列的头消一下交点队列的尾
如果最后直线队列长度小于 \(3\),那么无解。(其实要特判一下只有一点直线的情况,我们可以直接在开始插入四个超级直线解决)
还要记得把开头的直线和末尾的直线的交点加进去,最后所有交点组成的凸包是半平面交。

求面积就选择点 \(1\),从它开始分割很多三角形,用叉积除二求面积即可。

#include<bits/stdc++.h>
using namespace std;
const int QAQ=1010;
const double eps=1e-9,inf=1000;
int n,cnt,ccx;
struct dian {double x,y;} d[QAQ],jd[QAQ],ans[QAQ];
struct bian {dian x,y;double s;} l[QAQ],dui[QAQ];
double cha(dian a,dian b) {return a.x*b.y-a.y*b.x;}
dian operator + (dian a,dian b) {return {a.x+b.x,a.y+b.y};}
dian operator * (dian a,double b) {return {a.x*b,a.y*b};}
dian xl(dian a,dian b) {return {b.x-a.x,b.y-a.y};}
bool you(dian p,bian s) {return cha(xl(s.x,p),xl(s.x,s.y))>0;}
bool cmp1(bian a,bian b) {return (a.s==b.s)?you(b.x,a):a.s<b.s;}
dian jiao(bian a,bian b)
{
	dian o1=xl(a.x,a.y),o2=xl(b.x,b.y),o3=xl(b.x,a.x);
	double cab=cha(o3,o2)/cha(o2,o1);
	return a.x+o1*cab;
}
void work()
{
	for(int i=1;i<=cnt;i++)
		l[i].s=atan2(l[i].y.y-l[i].x.y,l[i].y.x-l[i].x.x);
	sort(l+1,l+cnt+1,cmp1);
	int zb=1,yb=0;
	dui[++yb]=l[1];
	for(int i=2;i<=cnt;i++)
	{
		if(fabs(l[i].s-l[i-1].s)<eps) continue;
		while(zb<yb&&you(jd[yb-1],l[i])) yb--;
		while(zb<yb&&you(jd[zb],l[i])) zb++;
		dui[++yb]=l[i];
		if(zb<yb) jd[yb-1]=jiao(dui[yb],dui[yb-1]);
	}
	while(zb<yb&&you(jd[yb-1],dui[zb])) yb--;
	while(zb<yb&&you(jd[zb],dui[yb])) zb++;
	if(yb-zb+1<=2) return ;
	jd[yb]=jiao(dui[zb],dui[yb]);
	for(int i=zb;i<=yb;i++) ans[++ccx]=jd[i];
}
signed main()
{
	cin>>n;
	for(int i=1,m;i<=n;i++)
	{
		cin>>m;
		for(int j=1;j<=m;j++) cin>>d[j].x>>d[j].y;
		for(int j=1;j<m;j++) l[++cnt]={d[j],d[j+1]};
		l[++cnt]={d[m],d[1]};
	}
	dian a={-inf,inf},b={inf,inf},c={-inf,-inf},d={inf,-inf};
	l[++cnt]={a,c},l[++cnt]={c,d},l[++cnt]={d,b},l[++cnt]={b,a};
	work();
	double da=0;
	for(int i=2;i<ccx;i++) da+=cha(xl(ans[1],ans[i]),xl(ans[1],ans[i+1]));
	printf("%.3f",da/2);
	return 0;
}

以上六个是我微会的,下面这几个也是我会的:

  1. 埃氏筛筛素数

以上是我会的所有数学东西。

posted @ 2025-09-17 22:20  _a1a2a3a4a5  阅读(9)  评论(0)    收藏  举报