ACM常用数学公式

转载: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.正弦定理

对于边长为 a, bc而相应角为 A, BC的三角形,有:
sinA / a = sinB / b = sinC/c
也可表示为:
a/sinA=b/sinB=c/sinC=2R
变形:a=2RsinA,b=2RsinB,c=2RsinC
其中R是三角形的外接圆半径。

   4.余弦定理

对于边长为a、b、c而相应角为A、B、C的三角形,有:
a² = b² + c²- 2bc·cosA
b² = a² + c² - 2ac·cosB
c² = a² + b² - 2ab·cosC
   5. 正切定理
对于边长为 a, bc而相应角为 A, BC的三角形,有:
(a+b)/(a-b) = tan[(A+B)/2]/tan[(A-B)/2]


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判断一次。

8.dp
 
1.完全背包公式
状态转移方程式为dp[i] = max(dp[i],dp[i-x]+1)(i-x>=0)



补充:

    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为最终结果;



--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------



已知三点坐标,求外接圆圆心坐标与半径。
a=((y2-y1)*(y3*y3-y1*y1+x3*x3-x1*x1)-(y3-y1)*(y2*y2-y1*y1+x2*x2-x1*x1))/(2.0*((x3-x1)*(y2-y1)-(x2-x1)*(y3-y1)));
b=((x2-x1)*(x3*x3-x1*x1+y3*y3-y1*y1)-(x3-x1)*(x2*x2-x1*x1+y2*y2-y1*y1))/(2.0*((y3-y1)*(x2-x1)-(y2-y1)*(x3-x1)));
r2=(x1-a)*(x1-a)+(y1-b)*(y1-b);


补充:

    转载自: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  圆与三角形 测试过了。

[cpp]  view plain  copy
  1. #include <cmath>  
  2. #include <queue>  
  3. #include <vector>  
  4. #include <cstdio>  
  5. #include <string>  
  6. #include <cstring>  
  7. #include <iomanip>  
  8. #include <iostream>  
  9. #include <algorithm>  
  10. using namespace std;  
  11.   
  12. //#pragma comment(linker, "/STACK:1024000000,1024000000")  
  13.   
  14. #define FIN             freopen("input.txt","r",stdin)  
  15. #define FOUT            freopen("output.txt","w",stdout)  
  16. #define fst             first  
  17. #define snd             second  
  18.   
  19. typedef __int64  LL;  
  20. //typedef long long LL;  
  21. typedef unsigned int uint;  
  22. typedef pair<intint> PII;  
  23.   
  24. const int INF = 0x3f3f3f3f;  
  25. const double eps = 1e-6;  
  26. const int MAXN = 3 + 5;  
  27. const int MAXM = 600 + 5;  
  28.   
  29. // 判断浮点数与0的大小关系  
  30. int sgn(double x) {  
  31.     if (fabs(x) < eps) return 0;  
  32.     if (x < 0) return -1;  
  33.     else return 1;  
  34. }  
  35.   
  36. struct Point {  
  37.     double x, y;  
  38.     Point() {}  
  39.     Point(double _x, double _y) : x(_x), y(_y) {}  
  40. } pc, p[MAXN];  
  41.   
  42. typedef Point Vect;  
  43. /** 
  44.  * 两点距离公式 
  45.  * 
  46.  */  
  47. double getDist(const Point &p1, const Point &p2) {  
  48.     int tx = p1.x - p2.x;  
  49.     int ty = p1.y - p2.y;  
  50.     return sqrt(tx * tx + ty * ty);  
  51. }  
  52.   
  53. /** 
  54.  * 由两点求向量 
  55.  * 
  56.  */  
  57. Vect getVect(const Point& p1, const Point &p2) {  
  58.     return Vect(p2.x - p1.x, p2.y - p1.y);  
  59. }  
  60.   
  61. /** 
  62.  * 求矢量叉积 
  63.  * @param  v1 [description] 
  64.  * @param  v2 [description] 
  65.  * @return    [description] 
  66.  */  
  67. double xmult(const Vect& v1, const Vect& v2) {  
  68.     return v1.x * v2.y - v2.x * v1.y;  
  69. }  
  70.   
  71. /** 
  72.  * 矢量叉积求面积 
  73.  * 
  74.  */  
  75. double getArea1(const Point &p0, const Point &p1, const Point &p2) {  
  76.     Vect v1 = getVect(p0, p1);  
  77.     Vect v2 = getVect(p0, p2);  
  78.     return 0.5 * getVectProduct(v1, v2);  
  79. }  
  80. /** 
  81.  * 海伦公式求面积 
  82.  * 
  83.  */  
  84. double getArea2(const Point &p0, const Point &p1, const Point &p2) {  
  85.     double p0p1 = getDist(p0, p1);  
  86.     double p0p2 = getDist(p0, p2);  
  87.     double p1p2 = getDist(p1, p2);  
  88.     double x = (p0p1 + p0p2 + p1p2) / 2.0;  
  89.     return sqrt(x * (x - p0p1) * (x - p0p2) * (x - p1p2));  
  90. }  
  91. /** 
  92.  * 利用海伦公式或者叉积公式求点到直线的距离 
  93.  * @param  p0 [点] 
  94.  * @param  p1 [直线上的点1] 
  95.  * @param  p2 [直线上的点2] 
  96.  * @return    [点到直线的距离] 
  97.  */  
  98. double point2line(const Point &p0, const Point &p1, const Point &p2) {  
  99.     double area = getArea1(p0, p1, p2);  
  100.     // double area = getArea2(p0, p1, p2);  
  101.     double p1p2 = getDist(p1, p2);  
  102.     return 2 * area / p1p2;  
  103. }  
  104. /** 
  105.  * 获取点到线段的最小距离 
  106.  * @param  p0 [点] 
  107.  * @param  p1 [线段端点1] 
  108.  * @param  p2 [线段端点2] 
  109.  * @return    [点到线段的距离] 
  110.  */  
  111. double point2lineSeg_Near(const Point &p0, const Point &p1, const Point &p2) {  
  112.     double p0p1 = getDist(p0, p1);  
  113.     double p0p2 = getDist(p0, p2);  
  114.     double p1p2 = getDist(p1, p2);  
  115.     // 点在线段上  
  116.     if (sgn(p0p1 + p0p2 - p1p2) == 0) return 0;  
  117.     // 线段两个端点p1,p2重合  
  118.     if (sgn(p1p2) == 0) return p0p1;  
  119.     // ∠p0p1p2 为直角或者钝角  
  120.     if (p0p2 * p0p2 >= p0p1 * p0p1 + p1p2 * p1p2) return p0p1;  
  121.     // ∠p0p2p1 为直角或者钝角  
  122.     if (p0p1 * p0p1 >= p0p2 * p0p2 + p1p2 * p1p2) return p0p2;  
  123.     // ∠p0p1p2 和 ∠p0p2p1 都是锐角,等价于求点到直线的距离  
  124.     return point2line(p0, p1, p2);  
  125. }  
  126. /** 
  127.  * 求点到线段的最长距离 
  128.  * @param  p0 [点] 
  129.  * @param  p1 [线段端点1] 
  130.  * @param  p2 [线段端点2] 
  131.  * @return    [最长距离] 
  132.  */  
  133. double point2lineSeg_Far(const Point &p0, const Point &p1, const Point &p2) {  
  134.     double p0p1 = getDist(p0, p1);  
  135.     double p0p2 = getDist(p0, p2);  
  136.     return max(p0p1, p0p2);  
  137. }  
  138.   
  139. int T;  
  140. double R;  
  141.   
  142. int main() {  
  143. #ifndef ONLINE_JUDGE  
  144.     FIN;  
  145. #endif // ONLINE_JUDGE  
  146.     scanf("%d", &T);  
  147.     while (T --) {  
  148.         scanf("%lf %lf %lf", &pc.x, &pc.y, &R);  
  149.         for (int i = 0; i < 3; i ++) {  
  150.             scanf("%lf %lf", &p[i].x, &p[i].y);  
  151.         }  
  152.         double mi[3], ma[3];  
  153.         mi[0] = point2lineSeg_Near(pc, p[0], p[1]);  
  154.         mi[1] = point2lineSeg_Near(pc, p[0], p[2]);  
  155.         mi[2] = point2lineSeg_Near(pc, p[1], p[2]);  
  156.         ma[0] = point2lineSeg_Far(pc, p[0], p[1]);  
  157.         ma[1] = point2lineSeg_Far(pc, p[0], p[2]);  
  158.         ma[2] = point2lineSeg_Far(pc, p[1], p[2]);  
  159.         bool suc = false;  
  160.         for (int i = 0; i < 3; i ++) {  
  161.             if (sgn(mi[i] - R) <= 0 && sgn(ma[i] - R) >= 0) {  
  162.                 suc = true;  
  163.                 break;  
  164.             }  
  165.         }  
  166.         puts(suc ? "Yes" : "No");  
  167.     }  
  168.     return 0;  
  169. }  

5.   判断三点共线

判断三点共线的方法可以通过求斜率,求周长,求面积来判断。

  1.  通过斜率来判断:(ay-by)/(ax-bx) == (cy-by)/(cx-bx)需要比较判断分母不为0 的情况,而且还可能出现除法精度丢失。
  2. 通过周长来判断:若AC > AB>BC,判断 AC == AB+BC,求距离的时候会用到sqrt,丢失精度。
  3. 通过面积来判断由上述的叉积求面积法来判断,面积为0,证明三点共线。

故,只需要判断即可。


6.判断四点是否共面

类似上面的方法, 可以根据 体积来判断。 四个点构成三个向量, 如果这三个向量的混合积为0,那么体积为0,那么四点共面。
代码如下【包括了三维空间的点积、叉积、混合积的计算】,代码已经在  51Nod 1265四点共面  中测试过了。
[cpp]  view plain  copy
  1. #include <cmath>  
  2. #include <queue>  
  3. #include <vector>  
  4. #include <cstdio>  
  5. #include <string>  
  6. #include <cstring>  
  7. #include <iomanip>  
  8. #include <iostream>  
  9. #include <algorithm>  
  10. using namespace std;  
  11.   
  12. //#pragma comment(linker, "/STACK:1024000000,1024000000")  
  13.   
  14. #define FIN             freopen("input.txt","r",stdin)  
  15. #define FOUT            freopen("output.txt","w",stdout)  
  16. #define fst             first  
  17. #define snd             second  
  18.   
  19. typedef __int64  LL;  
  20. //typedef long long LL;  
  21. typedef unsigned int uint;  
  22. typedef pair<intint> PII;  
  23.   
  24. const int INF = 0x3f3f3f3f;  
  25. const double eps = 1e-6;  
  26. const int MAXN = 4 + 5;  
  27. const int MAXM = 600 + 5;  
  28. int sgn(double x) {    
  29.     if (fabs(x) < eps) return 0;    
  30.     if (x < 0) return -1;    
  31.     else return 1;    
  32. }    
  33. struct Point {  
  34.     double x, y, z;  
  35. };  
  36. typedef Point Vect;  
  37. int T;  
  38. Point pnts[MAXN];  
  39. /** 
  40.  * 三维空间中两点求向量 
  41.  *  
  42.  */  
  43. Vect getVect(const Point& p1, const Point& p2) {  
  44.     Vect v;  
  45.     v.x = p1.x - p2.x;  
  46.     v.y = p1.y - p2.y;  
  47.     v.z = p1.z - p2.z;  
  48.     return v;  
  49. }  
  50. /** 
  51.  * 求三维空间的两向量叉积 (v1 × v2) 
  52.  *  
  53.  */  
  54. Vect xMulti(const Vect& v1, const Vect& v2) {  
  55.     Vect v;  
  56.     v.x = v1.y * v2.z - v1.z * v2.y;  
  57.     v.y = v1.z * v2.x - v1.x * v2.z;  
  58.     v.z = v1.x * v2.y - v1.y * v2.x;  
  59.     return v;  
  60. }  
  61. /** 
  62.  * 求三维空间中的两向量点积 (v1 · v2) 
  63.  *  
  64.  */  
  65. double dotMulti(const Vect& v1, const Vect& v2) {  
  66.     return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;  
  67. }  
  68. /** 
  69.  * 求三维空间中三个向量的混合积 (v1 × v2)·(v3) 
  70.  *  
  71.  */  
  72. double mixMulti(const Vect& v1, const Vect& v2, const Vect& v3) {  
  73.     return dotMulti(xMulti(v1, v2), v3);  
  74. }  
  75. /** 
  76.  * 判断四点是否共面 
  77.  * 根据混合积求体积,判断体积是否为0 
  78.  */  
  79. bool isInArea(const Point& p1, const Point& p2, const Point& p3, const Point& p4) {  
  80.     Vect p1p2, p1p3, p1p4;  
  81.     p1p2 = getVect(p1, p2);  
  82.     p1p3 = getVect(p1, p3);  
  83.     p1p4 = getVect(p1, p4);  
  84.     return sgn(mixMulti(p1p2, p1p3, p1p4)) == 0;  
  85. }  
  86. int main() {  
  87. #ifndef ONLINE_JUDGE  
  88.     FIN;  
  89. #endif // ONLINE_JUDGE  
  90.     scanf("%d", &T);  
  91.     while (T --) {  
  92.         for (int i = 0; i < 4; i ++) {  
  93.             scanf("%lf %lf %lf", &pnts[i].x, &pnts[i].y, &pnts[i].z);  
  94.         }  
  95.         bool ret = isInArea(pnts[0], pnts[1], pnts[2], pnts[3]);  
  96.         puts(ret ? "Yes" : "No");  
  97.     }  
  98.     return 0;  
  99. }  

6.判断线段是否相交

代码已经在  51 nod 1264 线段相交 测试过了
[cpp]  view plain  copy
  1. #include <cmath>  
  2. #include <queue>  
  3. #include <vector>  
  4. #include <cstdio>  
  5. #include <string>  
  6. #include <cstring>  
  7. #include <iomanip>  
  8. #include <iostream>  
  9. #include <algorithm>  
  10. using namespace std;  
  11.   
  12. //#pragma comment(linker, "/STACK:1024000000,1024000000")  
  13.   
  14. #define FIN             freopen("input.txt","r",stdin)  
  15. #define FOUT            freopen("output.txt","w",stdout)  
  16. #define fst             first  
  17. #define snd             second  
  18.   
  19. typedef __int64  LL;  
  20. //typedef long long LL;  
  21. typedef unsigned int uint;  
  22. typedef pair<intint> PII;  
  23.   
  24. const int INF = 0x3f3f3f3f;  
  25. const double eps = 1e-6;  
  26. const int MAXN = 4 + 5;  
  27. const int MAXM = 600 + 5;  
  28.   
  29. int sgn(double x) {  
  30.     if (fabs(x) < eps) return 0;  
  31.     if (x < 0) return -1;  
  32.     else return 1;  
  33. }  
  34.   
  35. struct Point {  
  36.     double x, y;  
  37.     Point() {}  
  38.     Point(double _x, double _y) : x(_x), y(_y) {}  
  39. } pnts[MAXN];  
  40.   
  41. typedef Point Vect;  
  42.   
  43. Vect getVect(const Point& p1, const Point &p2) {  
  44.     return Vect(p2.x - p1.x, p2.y - p1.y);  
  45. }  
  46. double xMulti(const Vect& v1, const Vect& v2) {  
  47.     return v1.x * v2.y - v2.x * v1.y;  
  48. }  
  49. /** 
  50.  * 判断线段是否相交 
  51.  *  
  52.  */  
  53. bool segInter(const Point& p1, const Point& p2, const Point& p3, const Point& p4) {  
  54.     return max(p1.x, p2.x) >= min(p3.x, p4.x) &&  
  55.            max(p3.x, p4.x) >= min(p1.x, p2.x) &&  
  56.            max(p1.y, p2.y) >= min(p3.y, p4.y) &&  
  57.            max(p3.y, p4.y) >= min(p1.y, p2.y) &&  
  58.            sgn(xMulti(getVect(p3, p2), getVect(p1, p2))) * sgn(xMulti(getVect(p4, p2), getVect(p1, p2))) <= 0 &&  
  59.            sgn(xMulti(getVect(p1, p4), getVect(p3, p4))) * sgn(xMulti(getVect(p2, p4), getVect(p3, p4))) <= 0;  
  60. }  
  61.   
  62. int T;  
  63.   
  64. int main() {  
  65. #ifndef ONLINE_JUDGE  
  66.     FIN;  
  67. #endif // ONLINE_JUDGE  
  68.     scanf("%d", &T);  
  69.     while(T --) {  
  70.         for(int i = 0; i < 4; i ++) {  
  71.             scanf("%lf %lf", &pnts[i].x, &pnts[i].y);  
  72.         }  
  73.         bool ret = segInter(pnts[0], pnts[1], pnts[2], pnts[3]);  
  74.         puts(ret ? "Yes" : "No");  
  75.     }  
  76.     return 0;  
  77. }  

补充:

    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=4else 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;
}
补充:
    

猜你喜欢

转载自blog.csdn.net/MallowFlower/article/details/80429501