转载:https://blog.csdn.net/qq_26891045/article/details/51490709
ACM常用数学公式汇总
1.扇形
1.扇形面积:S=1/2×弧长×半径,S扇=(n/360)πR²
2.三角函数
1.定义
基本函数
|
英文
|
缩写
|
表达式
|
语言描述
|
|
sine
|
sin
|
a/c
|
∠A的对边比斜边
| ||
cosine
|
cos
|
b/c
|
∠A的邻边比斜边
| ||
tangent
|
tan
|
a/b
|
∠A的对边比邻边
| ||
cotangent
|
cot
|
b/a
|
∠A的邻边比对边
| ||
secant
|
sec
|
c/b
|
∠A的斜边比邻边
| ||
cosecant
|
csc
|
c/a
|
∠A的斜边比对边
|
2.特殊角
3.正弦定理
4.余弦定理
3.面积
1.三角形面积
s=a*b*sinC/2
2.多边形面积
计算几何,求多边形的面积 实例:传送门
只要记住这个公式:
如果逆时针给出点坐标,值为正,
如果顺时针给出点坐标,值为负。
当i=n-1 i+1就是n所代表的点就是第一个点。
3.摆线留下的面积
摆线留下的面积等于圆的三倍 实例:传送门
4.点和直线
1.点到直线的距离(直线AX+BY+C=0):
2.两平行线之间的距离(直线AX+BY+C=0):
3.两直线的夹角(直线AX+BY+C=0):
5.多边形重心
1.三角形重心
设某个三角形的重心为G(cx,cy),顶点坐标分别为A1(x1,y1),A2(x2,y2),A3(x3,y3),则有cx = (x1 + x2 + x3)/3.同理求得cy
2.多边形重心
cx = (∑ cx[i]*s[i]) / (3*∑s[i]); cy = (∑ cy[i]*s[i] ) / (3*∑s[i]);其中(cx[i], cy[i]), s[i]分别是所划分的第i个三角形的重心坐标和面积 示例:传送门
6.判定公式
1.锐角三角形判定公式
锐角三角形计算公式:a*a+b*b>c*c
7.向量
1.向量之间的夹角
2.三角形的面积
三角形ABC的面积=
3.多边形的面积
同理可得: 或
4.向量叉积判断多边形凹凸
对于连续的三个点p0,p1,p2,另向量a=p1-p0,b=p2-p1若是凸多边形,那么b相对于a一定是向逆时针方向
旋转的。
判断两向量的旋转方向,可以使用向量的叉积 a×b = x1×y2 - x2×y1
a×b > 0 b在a的逆时针方向
a×b = 0 b平行于a(共线)
a×b < 0 b在a的顺时针方向
要注意的是,对于最后一个点pn,还要和起始的两个点p0,p1判断一次。
补充:
1.求三角形外心坐标
给定三角形三个顶点的坐标,如何求三角形的外心的坐标呢?
例如 :给定a(x1,y1) b(x2,y2) c(x3,y3)求外接圆心坐标O(x,y)
1. 首先,外接圆的圆心是三角形三条边的垂直平分线的交点,我们根据圆心到顶点的距离相等,可以列出以下方程:
(x1-x)*(x1-x)+(y1-y)*(y1-y)=(x2-x)*(x2-x)+(y2-y)*(y2-y);
(x2-x)*(x2-x)+(y2-y)*(y2-y)=(x3-x)*(x3-x)+(y3-y)*(y3-y);
2.化简得到:
2*(x2-x1)*x+2*(y2-y1)y=x2^2+y2^2-x1^2-y1^2;
2*(x3-x2)*x+2*(y3-y2)y=x3^2+y3^2-x2^2-y2^2;
令:A1=2*(x2-x1);
B1=2*(y2-y1);
C1=x2^2+y2^2-x1^2-y1^2;
A2=2*(x3-x2);
B2=2*(y3-y2);
C2=x3^2+y3^2-x2^2-y2^2;
即:A1*x+B1y=C1;
A2*x+B2y=C2;
3.最后根据克拉默法则:
x=((C1*B2)-(C2*B1))/((A1*B2)-(A2*B1));
y=((A1*C2)-(A2*C1))/((A1*B2)-(A2*B1));
因此,x,y为最终结果;
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
补充:
转载自:http://blog.csdn.net/acmore_xiong
1. 海伦公式求面积
公式描述:公式中a,b,c分别为三角形三边长,p为半周长,S为三角形的面积。
2. 矢量向量求面积
3. 点到直线的距离公式
方法一:距离公式直接求
公式描述:公式中的直线方程为Ax+By+C=0,点P的坐标为(x0,y0)。但是直线方程不是够直接。推荐使用方法二。
方法二:先用海伦公式求面积然后求三角形高
4. 点到线段的距离公式[或:点到线段最近的点]
有以下四种情况:
- 点在线段上,距离为0;
- 线段是一个点,用两点公式求;
- 三点构成直角三角形或者钝角三角形,那么直角或者钝角即为点到线段最近的点;
- 三点构成锐角三角形,那么距离为三角形的高,点到线段最近的点。
以下是具体代码, 代码已经在 51 Nod 1298 圆与三角形 测试过了。
- #include <cmath>
- #include <queue>
- #include <vector>
- #include <cstdio>
- #include <string>
- #include <cstring>
- #include <iomanip>
- #include <iostream>
- #include <algorithm>
- using namespace std;
- //#pragma comment(linker, "/STACK:1024000000,1024000000")
- #define FIN freopen("input.txt","r",stdin)
- #define FOUT freopen("output.txt","w",stdout)
- #define fst first
- #define snd second
- typedef __int64 LL;
- //typedef long long LL;
- typedef unsigned int uint;
- typedef pair<int, int> PII;
- const int INF = 0x3f3f3f3f;
- const double eps = 1e-6;
- const int MAXN = 3 + 5;
- const int MAXM = 600 + 5;
- // 判断浮点数与0的大小关系
- int sgn(double x) {
- if (fabs(x) < eps) return 0;
- if (x < 0) return -1;
- else return 1;
- }
- struct Point {
- double x, y;
- Point() {}
- Point(double _x, double _y) : x(_x), y(_y) {}
- } pc, p[MAXN];
- typedef Point Vect;
- /**
- * 两点距离公式
- *
- */
- double getDist(const Point &p1, const Point &p2) {
- int tx = p1.x - p2.x;
- int ty = p1.y - p2.y;
- return sqrt(tx * tx + ty * ty);
- }
- /**
- * 由两点求向量
- *
- */
- Vect getVect(const Point& p1, const Point &p2) {
- return Vect(p2.x - p1.x, p2.y - p1.y);
- }
- /**
- * 求矢量叉积
- * @param v1 [description]
- * @param v2 [description]
- * @return [description]
- */
- double xmult(const Vect& v1, const Vect& v2) {
- return v1.x * v2.y - v2.x * v1.y;
- }
- /**
- * 矢量叉积求面积
- *
- */
- double getArea1(const Point &p0, const Point &p1, const Point &p2) {
- Vect v1 = getVect(p0, p1);
- Vect v2 = getVect(p0, p2);
- return 0.5 * getVectProduct(v1, v2);
- }
- /**
- * 海伦公式求面积
- *
- */
- double getArea2(const Point &p0, const Point &p1, const Point &p2) {
- double p0p1 = getDist(p0, p1);
- double p0p2 = getDist(p0, p2);
- double p1p2 = getDist(p1, p2);
- double x = (p0p1 + p0p2 + p1p2) / 2.0;
- return sqrt(x * (x - p0p1) * (x - p0p2) * (x - p1p2));
- }
- /**
- * 利用海伦公式或者叉积公式求点到直线的距离
- * @param p0 [点]
- * @param p1 [直线上的点1]
- * @param p2 [直线上的点2]
- * @return [点到直线的距离]
- */
- double point2line(const Point &p0, const Point &p1, const Point &p2) {
- double area = getArea1(p0, p1, p2);
- // double area = getArea2(p0, p1, p2);
- double p1p2 = getDist(p1, p2);
- return 2 * area / p1p2;
- }
- /**
- * 获取点到线段的最小距离
- * @param p0 [点]
- * @param p1 [线段端点1]
- * @param p2 [线段端点2]
- * @return [点到线段的距离]
- */
- double point2lineSeg_Near(const Point &p0, const Point &p1, const Point &p2) {
- double p0p1 = getDist(p0, p1);
- double p0p2 = getDist(p0, p2);
- double p1p2 = getDist(p1, p2);
- // 点在线段上
- if (sgn(p0p1 + p0p2 - p1p2) == 0) return 0;
- // 线段两个端点p1,p2重合
- if (sgn(p1p2) == 0) return p0p1;
- // ∠p0p1p2 为直角或者钝角
- if (p0p2 * p0p2 >= p0p1 * p0p1 + p1p2 * p1p2) return p0p1;
- // ∠p0p2p1 为直角或者钝角
- if (p0p1 * p0p1 >= p0p2 * p0p2 + p1p2 * p1p2) return p0p2;
- // ∠p0p1p2 和 ∠p0p2p1 都是锐角,等价于求点到直线的距离
- return point2line(p0, p1, p2);
- }
- /**
- * 求点到线段的最长距离
- * @param p0 [点]
- * @param p1 [线段端点1]
- * @param p2 [线段端点2]
- * @return [最长距离]
- */
- double point2lineSeg_Far(const Point &p0, const Point &p1, const Point &p2) {
- double p0p1 = getDist(p0, p1);
- double p0p2 = getDist(p0, p2);
- return max(p0p1, p0p2);
- }
- int T;
- double R;
- int main() {
- #ifndef ONLINE_JUDGE
- FIN;
- #endif // ONLINE_JUDGE
- scanf("%d", &T);
- while (T --) {
- scanf("%lf %lf %lf", &pc.x, &pc.y, &R);
- for (int i = 0; i < 3; i ++) {
- scanf("%lf %lf", &p[i].x, &p[i].y);
- }
- double mi[3], ma[3];
- mi[0] = point2lineSeg_Near(pc, p[0], p[1]);
- mi[1] = point2lineSeg_Near(pc, p[0], p[2]);
- mi[2] = point2lineSeg_Near(pc, p[1], p[2]);
- ma[0] = point2lineSeg_Far(pc, p[0], p[1]);
- ma[1] = point2lineSeg_Far(pc, p[0], p[2]);
- ma[2] = point2lineSeg_Far(pc, p[1], p[2]);
- bool suc = false;
- for (int i = 0; i < 3; i ++) {
- if (sgn(mi[i] - R) <= 0 && sgn(ma[i] - R) >= 0) {
- suc = true;
- break;
- }
- }
- puts(suc ? "Yes" : "No");
- }
- return 0;
- }
5. 判断三点共线
判断三点共线的方法可以通过求斜率,求周长,求面积来判断。
- 通过斜率来判断:(ay-by)/(ax-bx) == (cy-by)/(cx-bx)需要比较判断分母不为0 的情况,而且还可能出现除法精度丢失。
- 通过周长来判断:若AC > AB>BC,判断 AC == AB+BC,求距离的时候会用到sqrt,丢失精度。
- 通过面积来判断:由上述的叉积求面积法来判断,面积为0,证明三点共线。
故,只需要判断即可。
6.判断四点是否共面
- #include <cmath>
- #include <queue>
- #include <vector>
- #include <cstdio>
- #include <string>
- #include <cstring>
- #include <iomanip>
- #include <iostream>
- #include <algorithm>
- using namespace std;
- //#pragma comment(linker, "/STACK:1024000000,1024000000")
- #define FIN freopen("input.txt","r",stdin)
- #define FOUT freopen("output.txt","w",stdout)
- #define fst first
- #define snd second
- typedef __int64 LL;
- //typedef long long LL;
- typedef unsigned int uint;
- typedef pair<int, int> PII;
- const int INF = 0x3f3f3f3f;
- const double eps = 1e-6;
- const int MAXN = 4 + 5;
- const int MAXM = 600 + 5;
- int sgn(double x) {
- if (fabs(x) < eps) return 0;
- if (x < 0) return -1;
- else return 1;
- }
- struct Point {
- double x, y, z;
- };
- typedef Point Vect;
- int T;
- Point pnts[MAXN];
- /**
- * 三维空间中两点求向量
- *
- */
- Vect getVect(const Point& p1, const Point& p2) {
- Vect v;
- v.x = p1.x - p2.x;
- v.y = p1.y - p2.y;
- v.z = p1.z - p2.z;
- return v;
- }
- /**
- * 求三维空间的两向量叉积 (v1 × v2)
- *
- */
- Vect xMulti(const Vect& v1, const Vect& v2) {
- Vect v;
- v.x = v1.y * v2.z - v1.z * v2.y;
- v.y = v1.z * v2.x - v1.x * v2.z;
- v.z = v1.x * v2.y - v1.y * v2.x;
- return v;
- }
- /**
- * 求三维空间中的两向量点积 (v1 · v2)
- *
- */
- double dotMulti(const Vect& v1, const Vect& v2) {
- return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
- }
- /**
- * 求三维空间中三个向量的混合积 (v1 × v2)·(v3)
- *
- */
- double mixMulti(const Vect& v1, const Vect& v2, const Vect& v3) {
- return dotMulti(xMulti(v1, v2), v3);
- }
- /**
- * 判断四点是否共面
- * 根据混合积求体积,判断体积是否为0
- */
- bool isInArea(const Point& p1, const Point& p2, const Point& p3, const Point& p4) {
- Vect p1p2, p1p3, p1p4;
- p1p2 = getVect(p1, p2);
- p1p3 = getVect(p1, p3);
- p1p4 = getVect(p1, p4);
- return sgn(mixMulti(p1p2, p1p3, p1p4)) == 0;
- }
- int main() {
- #ifndef ONLINE_JUDGE
- FIN;
- #endif // ONLINE_JUDGE
- scanf("%d", &T);
- while (T --) {
- for (int i = 0; i < 4; i ++) {
- scanf("%lf %lf %lf", &pnts[i].x, &pnts[i].y, &pnts[i].z);
- }
- bool ret = isInArea(pnts[0], pnts[1], pnts[2], pnts[3]);
- puts(ret ? "Yes" : "No");
- }
- return 0;
- }
6.判断线段是否相交
- #include <cmath>
- #include <queue>
- #include <vector>
- #include <cstdio>
- #include <string>
- #include <cstring>
- #include <iomanip>
- #include <iostream>
- #include <algorithm>
- using namespace std;
- //#pragma comment(linker, "/STACK:1024000000,1024000000")
- #define FIN freopen("input.txt","r",stdin)
- #define FOUT freopen("output.txt","w",stdout)
- #define fst first
- #define snd second
- typedef __int64 LL;
- //typedef long long LL;
- typedef unsigned int uint;
- typedef pair<int, int> PII;
- const int INF = 0x3f3f3f3f;
- const double eps = 1e-6;
- const int MAXN = 4 + 5;
- const int MAXM = 600 + 5;
- int sgn(double x) {
- if (fabs(x) < eps) return 0;
- if (x < 0) return -1;
- else return 1;
- }
- struct Point {
- double x, y;
- Point() {}
- Point(double _x, double _y) : x(_x), y(_y) {}
- } pnts[MAXN];
- typedef Point Vect;
- Vect getVect(const Point& p1, const Point &p2) {
- return Vect(p2.x - p1.x, p2.y - p1.y);
- }
- double xMulti(const Vect& v1, const Vect& v2) {
- return v1.x * v2.y - v2.x * v1.y;
- }
- /**
- * 判断线段是否相交
- *
- */
- bool segInter(const Point& p1, const Point& p2, const Point& p3, const Point& p4) {
- return max(p1.x, p2.x) >= min(p3.x, p4.x) &&
- max(p3.x, p4.x) >= min(p1.x, p2.x) &&
- max(p1.y, p2.y) >= min(p3.y, p4.y) &&
- max(p3.y, p4.y) >= min(p1.y, p2.y) &&
- sgn(xMulti(getVect(p3, p2), getVect(p1, p2))) * sgn(xMulti(getVect(p4, p2), getVect(p1, p2))) <= 0 &&
- sgn(xMulti(getVect(p1, p4), getVect(p3, p4))) * sgn(xMulti(getVect(p2, p4), getVect(p3, p4))) <= 0;
- }
- int T;
- int main() {
- #ifndef ONLINE_JUDGE
- FIN;
- #endif // ONLINE_JUDGE
- scanf("%d", &T);
- while(T --) {
- for(int i = 0; i < 4; i ++) {
- scanf("%lf %lf", &pnts[i].x, &pnts[i].y);
- }
- bool ret = segInter(pnts[0], pnts[1], pnts[2], pnts[3]);
- puts(ret ? "Yes" : "No");
- }
- return 0;
- }
补充:
https://wenku.baidu.com/view/b481511fb7360b4c2e3f6470.html
补充:
转载至:https://blog.csdn.net/qq_37383726/article/details/76532157
& o(n)筛出n以内数字的质因子个数。
Vis[0] = Vis[1] = true;
for(int i = 2; i < MAXN; i++) {
if(!Vis[i]) {
Primefactor[i] = 1;
for(int j = 2 * i; j < MAXN; j += i) {
Vis[j] = true;
Primefactor[j]++;
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
& 求一个区间所有数的所有因子的和 (包括自身和1)
LL sum[MAXN],sum[MAXN];
void dabiao(){// 打表因子和
for(int i=2;i*i<=MAXN;i++){
for(int j=i;i*j<=MAXN;j++){
if(i!=j) ans[j*i]+=i+j;
else ans[j*i]+=i;
}
}
sum[1]=1;//这里打表啦前缀和 来求区间的
for(int i=2;i<=MAXN;i++)
sum[i]=sum[i-1]+ans[i]+i+1;// 要加上 自身 和 1
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
& 欧拉筛 筛出每个数的最小非1因子
int mifac[maxn];bool prime[maxn]={0};
void init(){
for(int i=2;i<maxn;i++) mifac[i]=i;
for(int i=2;i<maxn;i++){
if(prime[i]==0){
for(int j=2;i*j<maxn;j++){
mifac[i*j]=min(mifac[i*j],i);
prime[i*j]=1;
}
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
bool su[MAXN + 1];
int mu[MAXN + 1], phi[MAXN + 1], prm[MAXN + 1], cnt;
inline void euler()
{
su[0] = su[1] = true;
mu[1] = 1;
phi[1] = 1;
for (int i = 2; i <= MAXN; i++) {
if (!su[i]) {
prm[++cnt] = i;
mu[i] = -1;
phi[i] = i - 1;
}
for (int j = 1; j <= cnt; j++) {
int t = i * prm[j];
if (t > MAXN) break;
su[t] = true;
if (i % prm[j] == 0) {
mu[t] = 0;
phi[t] = phi[i] * prm[j];
break;
} else {
mu[t] = -mu[i];
phi[t] = phi[i] * (prm[j] - 1);
}
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
< 1 > 欧拉函数的求解
欧拉函数 定义
性质
1 一个素数的比它小的互质数的个数为该数减一,ψ(P)=P-1。
2 假如ψ(N)的欧拉函数值为p,则N的最小值为大于p的最小素数。
两种
LL eular(LL n){ //单独求欧拉函数值
LL ans=n;
for(LL i=2;i*i<=n;i++){
if(n%i==0){
ans=ans/i*(i-1);
while(n%i==0) n/=i;
}
}
if(n>1) ans=ans/n*(n-1);
return ans;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
LL e[MAXN];//欧拉筛法
void eular(){
for(int i=0;i<MAXN;i++) e[i]=i;
for(int i=2;i<MAXN;i++)
if(e[i]==i)
for(int j=i;j<MAXN;j+=i) e[j]=e[j]/i*(i-1);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
&
bool su[MAXN]={1,1,0};//素筛
void shai(){
for(int i=2;i*i<=MAXN;i++)
if(!su[i])
for(int j=i*i;j<MAXN;j+=i)
su[j]=1;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
//筛出素数
int su[MAXN], prm[MAXN],sz;
void init() {
for(int i = 2; i < MAXN; ++i) {
if(!su[i]) prm[sz++] = i;
for(int j = 0; j < sz; ++j) {
int t = i * prm[j];
if(t >= MAXN) break;
su[t] = true;
if(i%prm[j] == 0) break;
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
& 在O(log n / log p)时间内求出n!的质因子分解中质数p的指数:(勒让德定理的简化算法)
inline int getn(int n, int p) { //n!的质因子p的指数
int sum = 0;
while (n) { n /= p; sum += n; }
return sum;
}
- 1
- 2
- 3
- 4
- 5
&
& 逆元
知识点链接
< 2 > 容斥原理
1)求数n的质因数
LL p[30],ge;
void getn(LL n){
ge=0;
for(LL i=2;i*i<=n;i++){
if(n%i==0) p[ge++]=i;
while(n%i==0) n/=i;
}
if(n>1) p[ge++]=n;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
2) 求[1,n] 区间内和m互质的个数
LL p[30],ge;
void getn(LL n){
ge=0;
for(LL i=2;i*i<=n;i++){
if(n%i==0) p[ge++]=i;
while(n%i==0) n/=i;
}
if(n>1) p[ge++]=n;
}
int que[MAXN],top;
LL nop(LL m){
top=0;
que[top++]=-1;
for(int i=0;i<ge;i++){
int t=top;
for(int j=0;j<t;j++)
que[top++]=(-1)*que[j]*p[i];
}
LL ans=0;
for(int i=1;i<top;i++) ans+=m/que[i];
return m-ans;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
3 ) 求q区间[1,n]和区间[1,n] 不重复的质数对==》求[1,n]的所有数字的欧拉函数的和
4)给定个数组arr和数n,问这个数组内有多少个数与m互质。
我门我可以先求能够被整除的个数,然后一减,就是不可以整除的个数。
LL gcd(LL a,LL b) { return b==0?a:gcd(b,a%b) ; }
LL lcm(LL a,LL b) { return a/gcd(a,b)*b ; }
LL arr[MAXN],ge; // 容斥定理
LL que[MAXN],top;
LL nop(LL m){
top=0;
que[top++]=-1;
for(int i=0;i<ge;i++){
LL temp=top;
for(int j=0;j<temp;j++){ // 这里也是控制了 奇加偶减。
LL f=1;
if(que[j]<0) f=-1;
que[top++]=f*lcm(abs(que[j]),p[i])*(-1);
}
}
LL sum=0;
for(LL i=1;i<top;i++){
sum+=m/que[i];
}
return m-sum; //sum中是能够被整除的不重复的个数
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
< 3 > 欧几里得
LL gcd(LL a,LL b) { return b==0?a:gcd(b,a%b) ; }
LL lcm(LL a,LL b) { return a/gcd(a,b)*b ; }
- 1
- 2
扩展欧几里得
用扩展欧几里得计算最小逆元
< 4 > 矩阵
1) 矩阵快速幂
常用来求递归式子的第n项
初始矩阵*过渡矩阵的k次幂==最后的结果
例题
下面代码是上述例题的代码
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int MAXN = 20;
const int MAXM = 1e6;
const int inf=0x3f3f3f3f;
LL mod,n;
struct Matrix {
LL a[MAXN][MAXN];
int h,w;
}ori,res,it;
LL f[20]={0,1,2,3,4,5,6,7,8,9}; // 初始函数值
void init(){
res.h=res.w=10;
memset(res.a,0,sizeof(res.a));//单位矩阵,结果矩阵
for(int i=1;i<=10;i++) res.a[i][i]=1;
ori.h=ori.w=10;
memset(ori.a,0,sizeof(ori.a));
//此处输入过渡矩阵
// puts("res ;");
// for(int i=1;i<=10;i++) {//输出 单位矩阵
// for(int j=1;j<=10;j++)
// printf("%lld ",res.a[i][j]);
// puts("");
// }
// puts("ori ;");
// for(int i=1;i<=10;i++) {//输出过渡矩阵
// for(int j=1;j<=10;j++)
// printf("%lld ",ori.a[i][j]);
// puts("");
// }
// puts("it ;"); // 输出初始矩阵
// for(int i=1;i<=1;i++) {
// for(int j=1;j<=10;j++)
// printf("%lld ",it.a[i][j]);
// puts("");
// }
}
Matrix multi(Matrix x,Matrix y){
Matrix z;
z.h=x.h;z.w=y.w;memset(z.a,0,sizeof(z.a));
for(int i=1;i<=x.h;i++){
for(int k=1;k<=x.w;k++){
if(x.a[i][k]==0) continue;
for(int j=1;j<=y.w;j++){
z.a[i][j]=(z.a[i][j]+x.a[i][k]*y.a[k][j]%mod)%mod;
}
}
}
return z;
}
void Matrix_mod(int n){
while(n){
if(n&1) res=multi(ori,res);
ori=multi(ori,ori);
n>>=1;
}
res=multi(it,res);//结果矩阵乘初始矩阵
printf("%lld\n",res.a[1][1]%mod);
}
int main(){
it.h=1;it.w=10;
for(int i=10;i>=1;i--) it.a[1][i]=f[10-i];
while(scanf("%lld%lld",&n,&mod)!=EOF){
for(int i=1;i<=10;i++){
scanf("%lld",&a[i]);
}
init();
if(n<10) printf("%lld\n",f[n]%mod);// 小于的时候应该输出 初值
else Matrix_mod(n-9); // 否则输出快速幂求解的
}
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
& 斐波那契的通项公式
取完对数之后
求第n项的前m位
又因为当n很大时,log10(1-((1-√5)/(1+√5))^n)->0
故原始可化为log10(an)=-0.5*log10(5.0)+((double)n)*log(f)/log(10.0); 最后取小数部分即可
代码
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int MAXN = 1e2;
const int MAXM = 1e5;
LL f[55]={0,1,1,2};
int main(){
for(int i=4;i<27;i++) {
f[i]=f[i-1]+f[i-2];
//printf("i== %d %lld\n",i,f[i]);
}
int n;
while(scanf("%d",&n)!=EOF){
if(n<=25) printf("%d\n",f[n]) ;
else {
double temp=-0.5*log(5.0)/log(10.0)+((double)n)*log((sqrt(5.0)+1.0)/2.0)/log(10.0);
temp-=floor(temp);
temp=pow(10.0,temp);
while(temp<10000) temp*=10; // 这里是前五位
printf("%d\n",(int)temp);
}
}
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
& 一般的求一个数字的前n位
double x,temp;
while(scanf("%lf",&x)!=EOF)
{
temp=log(x)/log(10.0);
temp=temp-floor(temp); //floor(temp)函数求出小于temp的最大整数
temp=pow(10.0,temp);
while(temp<1000)// 此处是四位
temp*=10;
//printf("%.0lf\n",temp); //采用浮点表达法时会四舍五入
printf("%d\n",(int)temp);//此处不需四舍五入,直接舍弃后面的位
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
& 判断n!是否能够被m整除
&因子和的计算方法
因子和:一个数的所以因子的和就叫因子和。。。
举个例子:12的因子和为:1+2+3+4+6+12
计算方法是把12分解为质因数的表达形式2^2*3
那么他的因子和就是:(1+2+2^2)*(1+3) // 其实每一个都可以用等比数列求和公式
证明写起来比较麻烦,大体上思路就是牛顿二项式。。
&高斯公式
& 哥德巴赫猜想
一个大偶数(>=4)必然可以拆分为两个素数的和,虽然目前还没有人能够从理论上进行证明,不过我根据科学家们利用计算机运算的结果,如果有一个偶数不能进行拆分,那么这个偶数至少是一个上百位的数!!
所以在ACM的世界中(数据量往往只有2^63以下)哥德巴赫猜想是成立的!!所以拆分程序一定能够实现的
哥德巴赫猜想的推广
任意一个>=8的整数一定能够拆分为四个素数的和
先来说8=2+2+2+2,(四个最小素数的和)不能再找到比2小的素数了,所以当n小于8,就一定不可能拆分为四个素数的和!
那么当n大于等于8,可以分情况讨论:
(1)n&1==0(n为偶数),那么n就一定可以拆分为两个偶数的和
那么根据哥德巴赫猜想,偶数可以拆分为两个素数的和,于是,n一定可以拆分为四个素数的和
(2)n&1==1(n为奇数),n一定可以拆分为两个偶数+1
由于有一个素数又是偶数,2,那么奇数一定有如下拆分:2+3+素数+素数
& 抽屉原理
如果现在有3个苹果,放进2个抽屉,那么至少有一个抽屉里面会有两个苹果
抽屉原理的运用扩展
现在假设有一个正整数序列a1,a2,a3,a4…..an,试证明我们一定能够找到一段连续的序列和,让这个和是n的倍数,该命题的证明就用到了抽屉原理
先构造一个序列si=a1+a2+…ai
然后分别对于si取模,如果其中有一个sk%n==0,那么a1+a2+…+ak就一定是n的倍数(该种情况得证)
下面是上一种情况的反面,即任何一个sk对于n的余数都不为0
对于这种情况,我们可以如下考虑,因为si%n!=0
那么si%n的范围必然在1——(n-1),所以原序列si就产生了n个范围在1——(n-1)的余数,于是抽屉原理就来了,n个数放进n-1个盒子里面,必然至少有两个余数会重复,那么这两个sk1,sk2之差必然是n的倍数,
而sk1-sk2是一段连续的序列,那么原命题就得到了证明了
& 立方和 公式
计算结果如下: 1³+2³+3³+…+n³=(n*(n+1)/2)²
& 求约数的个数
例题
& 求一个定积分的值
例题
Simpson`s 3/8 rule
double a1,b1;
inline double f(double x){ // 被积函数,据题而定
return a1*x+b1;
}
inline double getappr(double a,double b){
return (b-a)*(f(a)+f(b)+3*f((2*a+b)/3)+3*f((a+2*b)/3))/8.0;
}
double simpson(double l,double r) { // 近似计算 积分
double sum=getappr(l,r);
double mid=(l+r)/2;
double suml=getappr(l,mid);
double sumr=getappr(mid,r);
return fabs(sum-suml-sumr)<eps?sum:simpson(l,mid)+simpson(mid,r);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
& n!的末尾有几个0
int f(int n) {// n!末尾有几个0
int ans=0;
while(n){
ans+=n/5;
n/=5;
}
printf("%d\n",ans);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
& 进制转换
int main(){
int n;int r; // n转r进制
while(scanf("%d%d",&n,&r)!=EOF){
int f=1; if(n<0) f=-1; n=abs(n);
string s="";
while(n){
int k=n%r;
if(k<10) s+=k+'0';
else s+=k+'A'-10;
n/=r;
}
if(f==-1)putchar('-') ;
reverse(s.begin(),s.end());
cout<<s<<endl;
}
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
& 将分数a/b化为小数后,小数点后第n位的数字是多少?
输入 a b n 输出 第n位数字
公式 (a*10^(n-1)%b)*10/b 优先级从左到右依次
代码
LL power(LL a,LL b,LL c)
{
LL s=1,base=a;
while(b)
{
if(b&1) s=s*base%c;
base=base*base%c;
b>>=1;
}
return s%c;
}
int main()
{
LL a,b,n;//a/b小数点后第n位
while(~scanf("%lld%lld%lld",&a,&b,&n))
{
LL c=((a%b)*(power(10,n-1,b)))%b;
printf("%lld\n",c*10/b);
}
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
& 把一个正整数n拆分成若干个正整数的和,请求出这些数乘积的最大值。
根据指数函数 可以知道相同的数字越多越好,所以 只能是 2 和 3 的加减,
另外 2*2*2<3*3
代码
LL power(LL a,LL b,LL c){
LL s=1,base=a%c;
while(b){
if(b&1) s=s*base%c;
base=base*base%c;
b>>=1;
}
return s;
}
int main(){
LL n;
scanf("%lld",&n);
if(n<4) printf("%lld\n",n);
else{
if(n%3==0) printf("%lld\n",power(3,n/3,mod));
else if(n%3==1) printf("%lld\n",(4*power(3,n/3-1,mod))%mod); //多余的一个1和去掉的一个3组合成2*2=4;
else if(n%3==2) printf("%lld\n",(2*power(3,n/3,mod))%mod);//
}
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
& 判断组合数C(n,m)的奇偶性: 当n&m==m为奇数,反之就是偶数
& n的k进制数的位数是多少
double a[M];
void dabiao(){//n的k进制数的位数是多少
double d=0; a[0]=0.0;
for(int i=1;i<M;i++) { d+=log(i); a[i]=d; }
}
int main(){
dabiao(); int n,m;
scanf("%d%d",&n,&m);
printf("%d\n",int(a[n]/log(m))+1);
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
& n!有多少位
LL n;
scanf("%lld",&n);
LL sum=1+0.5*log10(2*pi*n)+n*log10(n/e);// 阶乘近似公式
printf("%lld\n",sum);
- 1
- 2
- 3
- 4
& 求逆序对 归并排序【有元素重复也可以用】
int a[MAXN],temp[MAXN];
LL ans=0;
int n;
void merge(int le,int mid,int ri){
int i,j,k;
i=le;j=mid+1;k=le;
for(;i<=mid&&j<=ri;){
if(a[i]>a[j]){
temp[k++]=a[j++];
ans+=mid-i+1;
}else temp[k++]=a[i++];
}
while(i<=mid) temp[k++]=a[i++];
while(j<=ri) temp[k++]=a[j++];
for(i=le;i<=ri;i++) a[i]=temp[i];
}
void merge_sort(int le,int ri){
if(le<ri){
int mid=(le+ri)>>1;
merge_sort(le,mid);
merge_sort(mid+1,ri);
merge(le,mid,ri);
}
}
int main(){
while(~scanf("%d",&n)){
for(int i=0;i<n;i++) scanf("%d",&a[i]);
ans=0;
merge_sort(0,n-1);
printf("%lld\n",ans);
}
return 0;
}
补充: