学到后面数学越来越多了,感觉好难啊,开个博客专门记录一下数学相关的东西
因为反正也没人看,所以主要还是给自己看的
一些符号:
数论函数的卷积:$ast$,$ h = f ast g$ 则 $h(n)=sum_{d|n}f(d)g(frac{n}{d})$
$epsilon $ 叫单位元,对每个 $f(1) eq 0$ 的函数 $f$,有 $epsilon ast f = f$
$epsilon(n) = [ n=1 ]$
$mathbf{id}$ ,不知道叫啥,反正 $mathbf{id}(n)=n$ ,没了
$mathbf{1}$ ,奇怪的操作,数字 $1$ 也能当函数,$mathbf{1}(n)=1$
$phi $,欧拉函数,有很多结论:
$mathbf{id}=phi ast mathbf{1}$,即 $n=sum_{d|n}phi(d)$
对于某个函数 $f$ 的逆 $g$,有 $f ast g = epsilon$
$mu $,莫比乌斯函数,$mu $ 其实是 $mathbf{1}$ 的逆
所以有 $phi = mu ast mathbf{id}$
关于如何求出 $mu(n)$ 的值 :
如果 $n$ 质因数分解以后每个质因数都互不相同,设质因数数量为 $p$,则 $mu(n)=(-1)^p$,否则 $mu(n)=0$
$sum_{d|n}mu(d)=[n=1]$
莫比乌斯反演: 设 $F(n)=sum_{d|n}f(d)$,那么有 $f(n)=sum_{d|n}mu(frac {n} {d})F(d)$
证明:
$f(n)=sum_{m|n}[frac {n} {m}=1] f(m)$
$f(n)=sum_{m|n}sum_{d|frac {n} {m}}mu(d)f(m)$,枚举 $d$
$f(n)=sum_{d|n}mu(d)sum_{m|frac {n} {d}}f(m)$
$f(n)=sum_{d|n}mu(d)F(frac {n} {d})$
$f(n)=sum_{d|n}mu(frac {n} {d})F(d)$
另一个方向的结论:$F(n)=sum_{n|d}f(d)$,那么有 $f(n)=sum_{n|d}mu(frac {d} {n})F(d)$
证明和上面差不多
二项式反演(就是容斥):
首先
$sum_{k=0}^{n}(-1)^kinom{n}{k}=[n=0]$,证明可以通过递推式,数学归纳法解决
$n=0$ 时式子为 $1$,$n$ 等于 $1$ 时式子为 $0$,考虑 $n+1$ 都是由 $n$ 得到的
对于每一个 $inom{n}{k}$ 他会贡献给 $inom{n+1}{k},inom{n+1}{k+1}$,因为 $(-1)^k,(-1)^{k+1}$ 正负不同刚好抵消,所以 $n+1$ 还是 $0$
设 $F(n)=sum_{k=0}^{n}inom{n}{k}f(k)$,那么有 $f(n)=sum_{k=0}^{n}(-1)^{n-k}inom{n}{k}F(k)$
证明:
$f(n)=sum_{m=0}^{n}[n-m=0]inom{n}{m}f(m)$
$f(n)=sum_{m=0}^{n}sum_{k=0}^{n-m}(-1)^kinom{n-m}{k}inom{n}{m}f(m)$
发现 $inom{n-m}{k}inom{n}{m}$ 意思是 $n$ 选 $m$ 剩下的再选 $k$ ,和 $n$ 选 $k$,剩下选 $m$ 是一样的
$f(n)=sum_{m=0}^{n}sum_{k=0}^{n-m}(-1)^kinom{n}{k}inom{n-k}{m}f(m)$,枚举 $k$
$f(n)=sum_{k=0}^{n}(-1)^kinom{n}{k}sum_{m=0}^{n-k}inom{n-k}{m}f(m)$
$f(n)=sum_{k=0}^{n}(-1)^kinom{n}{k}F(n-k)$,换一下下标:
$f(n)=sum_{k=0}^{n}(-1)^{n-k}inom{n}{k}F(k)$
杜教筛相关:
$S_{f}$ 表示 $f$ 的前缀和,即 $S_{f}(n)=sum_{i=1}^{n}f(i)$
$S_{f ast g} = sum_{d=1}^{n} g(d)S_{f}(left lfloor frac{n}{d} ight floor)$
证明:
$sum_{i=1}^{n}sum_{d|i}f(d)g(frac {i} {d})=sum_{i=1}^{n}sum_{d|i}f(frac {i} {d})g(d)$
考虑枚举因数 $d$,显然有 $n/d$ 种 $i$,并且每种都是 $d$ 的倍数,设 $i=dj$
$=sum_{d=1}^{n}g(d)sum_{j}^{left lfloor frac{n}{d} ight floor}f(j)$
$= sum_{d=1}^{n} g(d)S_{f}(left lfloor frac{n}{d} ight floor)$
所以有 $g(1)S_f(n)=S_{f ast g}-sum_{i=2}^{n} g(i)S_{f}(left lfloor frac{n}{i} ight floor)$
因为 $mu ast mathbf{1} = epsilon$, $S_{epsilon}(n)=1$
所以 $S_{mu}(n)=1-sum_{i=2}^{n}1 cdot S_{mu}(left lfloor frac{n}{i} ight floor)$
$S_{mu}(n)=1-sum_{i=2}^{n}S_{mu}(left lfloor frac{n}{i} ight floor)$
因为 $phi ast mathbf{1} = mathbf{id}$,$S_{mathbf{id}}(n)=frac {n(n+1)} {2}$
所以 $S_{phi}(n)=frac {n(n+1)} {2} - sum_{i=2}^{n} 1 cdot S_{phi}(left lfloor frac{n}{i} ight floor)$
$S_{phi}(n)=frac {n(n+1)} {2} - sum_{i=2}^{n}S_{phi}(left lfloor frac{n}{i} ight floor)$
设 $f=phi cdot id$,因为 $(f ast mathbf{id})(n)=sum_{d|n}f(d) cdot (frac {n} {d})= sum_{d|n}phi(d) cdot d cdot (frac {n} {d})=nsum_{d|n}phi(d)=n^2$
所以 $S_{f ast mathbf{id}}(n)=n^2$
所以 $S_{f}(n)=n^2 - sum_{i=2}^{n}i cdot S_{f}(left lfloor frac{n}{i} ight floor)$
生成函数相关:
$sum_{n=0}^{infty }x^n = frac {1} {1-x}$
$sum_{n=0}^{infty }inom{n+k-1}{n}x^n = frac {1} {(1-x)^k}$
$sum_{n=0}^{infty }frac {x^n} {n!} = e^x$
$sum_{n=0}^{infty }frac {x^n} {n} = ln frac {1} {1-x}$
$sum_{n=0}^{infty }frac {x^{2n}} {(2n)!} = frac {e^x+e^{-x}} {2}$
$sum_{n=0}^{infty }frac {x^{2n+1}} {(2n+1)!} = frac {e^x-e^{-x}} {2}$
泰勒展开:$F(x)=sum_{i=0}^{infty} frac {F^{(i)}(x_0)(x-x_0)^i} {i!}$
群论相关:
符号:
$G$ 置换群
$Z_k$ 保持 $k$ 这个位置不变的置换集合
$E_k$ $k$ 这个位置改变的的元素集合
$C(pi)$ 置换 $pi$ 作用下不变的位置 $k$ 的个数
$Burnside$ 引理: $L= frac{1} {left |G ight |}sum_{i=1}^{n}left | Z_i ight |=frac{1} {left |G ight |}sum_{pi in G}C(pi)$
$Polya$ 定理: $ L= frac {1} {left |G ight |} (m^{c(pi_1)}+m^{c(pi_2)}+m^{c(pi_3)}+...+m^{c(pi_p)})$
其中 $m$ 是颜色数,$c(pi_k)$ 是置换 $pi_k$ 的循环节个数
博弈论(以下均为口胡):
博弈的每个状态都可以看成点,一个状态经过一些操作到达另一个状态看成有向边,整个博弈是个 $DAG$
一些定义:$mex$ ,一种对整数集合的操作,输入一个集合,输出一个数,为集合中没出现的最小的整数,如 $mex(0,1,3,4)=2,mex(1,2,3)=0$
$SG$ 函数,定义为所有它能到达的点的 $SG$ 值的 $mex$,如果它不能到达任何点,$SG=0$
结束局面为必败局面,能到达必败局面的是必胜局面,所有到达的局面都是必胜局面的是必败局面(十分显然)
发现这样和 $SG$ 有很大关联,如果 $SG>0$ 说明有一个后继局面 $SG=0$,如果 $SG=0$ 说明不是结束局面就是所有到达的局面 $SG>0$
所以对于单个博弈如果 $SG=0$ 则为必败局面,$SG>0$ 则为必胜局面
对于多个子博弈一起进行的博弈(子博弈之间互不干扰),这个总的博弈的 $SG$ 为所有子博弈 $SG$ 的异或和(严谨证明好像要很多神仙操作,看不懂溜了)
总结一下就是单个博弈 $SG$ 是取 $mex$ ,多个博弈 $SG$ 取 $xor$
$Anti-SG$,面对没有后继的状态的人赢,如果规定当局面所有单一游戏 $SG$ 都是 $0$ 时游戏结束
那么先手必胜当且仅当:
整个游戏的 $SG>0$ 并且存在子博弈的 $SG>1$,或者
整个游戏的 $SG=0$ 并且任意子博弈的 $SG<=1$
具体证明我也讲不清楚,大概就是把 整个游戏的 $SG$ 是否为 $0$,是否存在子博弈 $SG>1$ ,分四种情况情况分别讨论
然后根据结束状态 总 $SG=0$,子 $SG=0$ 数学归纳一下,真想探究的话走这边:传送门
$multi-SG$ ,单一博弈的一个后继可以是 多个单一博弈的总博弈 ,这个东西同样满足 $SG$ 函数
即每个博弈的 $SG$ 值为所有后继博弈的 $SG$ 值异或和
计算几何各种基础操作(毒瘤警告):
自己整理的,并不能保证正确性 $qwq$,如果有大佬发现错误希望能说一声,感激不尽 $qwq$
以下总计 $6.32kb$
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; typedef long long ll; typedef double db; typedef long double ldb; const db eps=1e-12;
inline int dcmp(db x) { if(fabs(x)<eps) return 0; return x<0 ? -1 : 1; }//判断正负
struct Point {//定义点或者向量 db x,y; Point (db a=0,db b=0) { x=a,y=b; } inline Point operator + (const Point &tmp) const {//向量加 return Point(x+tmp.x,y+tmp.y); } inline Point operator - (const Point &tmp) const {//向量减 return Point(x-tmp.x,y-tmp.y); } inline Point operator * (const db k) const {//向量数乘 return Point(x*k,y*k); } inline bool operator != (const Point &tmp) const { return fabs(x-tmp.x)>eps||fabs(y-tmp.y)>eps; } inline bool operator < (const Point &tmp) const {//把点按x,y排序 return x!=tmp.x ? x<tmp.x : y<tmp.y; } inline void print() { cout<<x<<" "<<y<<endl; }//输出 };
inline db Cross(Point A,Point B) { return A.x*B.y-A.y*B.x; }//叉积
inline db Dot(Point A,Point B) { return A.x*B.x+A.y*B.y; }//点积
inline bool In_Line(Point A,Point B,Point C) {//判断A是否在BC上 if(fabs(Cross(B-A,C-A))<eps&& Dot(B-A,C-A)<-eps) return 1; }
inline db Polar_Angle(Point A) {//求向量A与x轴的极角 return atan2(A.y,A.x); }
inline Point Rotate(Point A,db a) {//把向量A旋转弧度a return Point(A.x*cos(a)-A.y*sin(a),A.x*sin(a)+A.y*cos(a)); }
inline db Length(Point A) {//求向量A的长度 return sqrt(Dot(A,A)); }
inline db Angle(Point A,Point B) {//求向量A,B之间的夹角 return acos(Dot(A,B)/Length(A)/Length(B)); }
inline db Distance_To_Line(Point P,Point A,Point B) {//求P到直线AB的距离 return fabs(Cross(B-A,P-A)/Length(B-A)); }
inline Point Intersection(Point a1,Point a2,Point b1,Point b2)//求直线a1a2,b1b2的交点 { Point a=a2-a1,b=b2-b1,c=b1-a1; if(fabs(Cross(b,a))<eps) return Point(-1e9,-1e9); db t=Cross(b,c)/Cross(b,a); return a1+a*t; }
void Tubao1()//按x,y排序求凸包 { sort(P+1,P+n+1); st[++Top]=P[1]; for(int i=2;i<=n;st[++Top]=P[i],i++) while(Top>1&& Cross(P[i]-st[Top-1],st[Top]-st[Top-1])>-eps ) Top--; //此处忽略加入凸包集合的代码 st[Top=1]=p[n]; for(int i=n-1;i;st[++Top]=P[i],i--) while(Top>1 && Cross(P[i]-st[Top-1],st[Top]-st[Top-1])>-eps ) Top--; //此处忽略加入凸包集合的代码 }
inline bool cmp(const Point &A,const Point &B) { return Cross(A,B)>0||( Cross(A,B)==0&&Length(A)<Length(B) ); }//按极角排序
void Tubao2()//按极角求凸包 { sort(P+1,P+n+1); for(int i=1;i<=n;i++) A[i]=A[i]-A[1]; sort(P+1,P+n+1,cmp); for(int i=1;i<=n;st[++Top]=P[i],i++) while(Top>1 && Cross(P[i]-st[Top-1],st[Top]-st[Top-1])>-eps ) Top--; n=Top; for(int i=1;i<=n;i++) P[i]=st[i]; }
inline bool Is_Point_In_Polygon(Point P,Point *poly)//判断点是否在多边形内 { /*从下往上穿过射线的边包含起点不包含终点 从上往下穿过射线的边包含终点不包含起点 这样若穿过的端点所在的两边同向则只被计算一次 若穿过的端点所在的边反向则要么一次都不计算,要么直接算两次*/ int cnt=0; for(int i=1;i<=n;i++) { if(In_Line(P,poly[i],poly[i%n+1])) return 1; int k=dcmp( Cross(poly[i%n+1]-poly[i],P-poly[i]) ); int d1=dcmp(poly[i].y-P.y); int d2=dcmp(poly[i%n+1].y-P.y); if(k>0&&d1<=0&&d2>0) cnt++; if(k<0&&d2<=0&&d1>0) cnt++; } return cnt&1; }
inline bool Is_Point_In_Tubao(Point P,Point *poly)//判断点P是否在凸包内,此处凸包按极角排序,poly[1]=(0,0) { if(Cross(P,poly[1])>eps||Cross(poly[n],P)>eps) return 0; ll pos=lower_bound(poly+1,poly+n+1,P,cmp)-poly-1; return dcmp( Cross(P-poly[pos],poly[pos%n+1]-poly[pos]) )<=0; }
inline db Get_Area(Point *poly)//求多边形面积,此处多边形按极角排序 { db res=0; for(int i=2;i<n;i++) res+=Cross(poly[i]-poly[1],poly[i+1]-poly[1]); return res/2; }
inline Point Get_Triangle_Center_of_gravity(Point A,Point B,Point C) { return Point((A.x+B.x+C.x)/3,(A.y+B.y+C.y)/3); }
struct Line {//定义有向直线 Point p,v; db ang; Line (Point A,Point B) { p=A,v=B; ang=atan2(v.y,v.x); } inline bool Is_Right(Point G) { return Cross(G-p,v)>0; }//判断G是否在直线右边 };
inline bool cmp2(Line &A,Line &B) { return dcmp(A.ang-B.ang)!=0 ? A.ang<B.ang : B.Is_Right(A.p); }//把直线按极角排序
inline Point Intersection(Line A,Line B)//求直线交点 { Point u=A.p-B.p,v=A.v,w=B.v; db t=Cross(w,u)/Cross(v,w); return A.p+A.v*t; }
void Get_Half_Plane_Intersection(Line *P)//半平面交 { sort(P+1,P+n+1,cmp2); int m=n,L=1,R=0; n=0; for(int i=1;i<=m;i++) if( dcmp(P[i].ang-P[i+1].ang)!=0||i==m ) P[++n]=P[i]; for(int i=1;i<=n;i++) { while(L<R && P[i].Is_Right(Intersection(Q[R],Q[R-1])) ) R--; while(L<R && P[i].Is_Right(Intersection(Q[L],Q[L+1])) ) L++; Q[++R]=P[i]; } while(L<R && Q[L].Is_Right(Intersection(Q[R],Q[R-1])) ) R--; while(L<R && Q[R].Is_Right(Intersection(Q[L],Q[L+1])) ) L++; n=0; Q[R+1]=Q[L]; for(int i=L;i<=R;i++) P[++n]=Intersection(Q[i],Q[i+1]); }
inline db Get_Triangle_Area(Point A,Point B,Point C) {//求三角形面积 return fabs(Cross(B-A,C-A)/2); }
//旋转卡壳 void RotatingCaliper_diameter(Point *poly) { db res=0; for(int i=1,p=1;i<=n;i++) { //可以同时卡多个点 while( Get_Triangle_Area(poly[i],poly[i+1],poly[p%n+1]) >= Get_Triangle_Area(poly[i],poly[i+1],poly[p]) ) p=p%n+1; res=max(res, max(Length(poly[p]-poly[i]),Length(poly[p]-poly[i+1])) ); } }
//最小圆覆盖 inline Point Roatate_90_Angle(Point A) { return Point(A.y,-A.x); } struct Circle {//定义圆 Point O; db r; Circle (Point a,db b=0) { O=a,r=b; } inline bool Is_Out_Of_Circle(Point G) { return r*r<Dot(O-G,O-G); } }; Circle Get_Circle(Point A,Point B,Point C)//由三点确定一个圆 { Line p1=Line((A+B)*0.5,Roatate_90_Angle(B-A)); Line p2=Line((B+C)*0.5,Roatate_90_Angle(B-C)); Point O=Intersection(p1,p2); return Circle(O,sqrt(Dot(O-A,O-A))); } void Get_Minest_Cricle(Point *P)//主过程 { random_shuffle(P+1,P+n+1); for(int i=1;i<=n;i++) { if(!C.Is_Out_Of_Circle(P[i])) continue; C=Circle(P[i],0); for(int j=1;j<i;j++) { if(!C.Is_Out_Of_Circle(P[j])) continue; C=Circle( (P[i]+P[j])*0.5 , sqrt(Dot(P[i]-P[j],P[i]-P[j]))*0.5 ); for(int k=1;k<j;k++) if(C.Is_Out_Of_Circle(P[k])) C=Get_Circle(P[i],P[j],P[k]); } } }
欧拉函数
$varphi (n)=ncdot frac{prod_{i=1}^{k}P_i-1 }{prod_{i=1}^{k}P_i }$
证明过程:把 $n$ 唯一分解可得:
$varphi (n)=varphi (prod _{i=1}^kprod _{j=1}^{a_i}P_i)$
因为如果A,B互质,$varphi (AB)=varphi (A)varphi (B)$
所以
$varphi (prod _{i=1}^kprod _{j=1}^{a_i}P_i) =prod _{i=1}^{k}varphi(P_i^{a_i})$
因为 $varphi(P^a)=(P-1)cdot P^{a-1}$(可以参考欧拉筛的过程)
所以
$prod _{i=1}^kvarphi(P_i^{a_i}) =prod _{i=1}^k((P_i-1)P^{a_i-1})=frac{prod _{i=1}^k((P_i-1)P_{i}^{a_i})}{prod _{i=1}^kP_i}$
把分子稍微拆开一下
$frac{prod _{i=1}^k((P_i-1)P_{i}^{a_i})}{prod _{i=1}^kP_i}=frac{prod _{i=1}^k(P_i-1)prod _{i=1}^kP_{i}^{a_i}}{prod _{i=1}^{k}P_i}$
然后发现分子后面一部分就是 $n$,所以原式就是
$frac{prod _{i=1}^k(P_i-1)cdot n}{prod _{i=1}^{k}P_i}$
$varphi (n)=ncdot frac{prod_{i=1}^{k}P_i-1 }{prod_{i=1}^{k}P_i }$
然后根据这个式子我们可以推出:
$varphi (xy)=frac{varphi(x)varphi(y)d }{varphi(d) } ,d=gcd(x,y)$
(待续)