一些数学几何知识和小技巧

16 篇文章 0 订阅
9 篇文章 2 订阅

发现自己几何sb,还是总结一下

已知三点求圆心,但三点不能共线

Point Getcir(Point A,Point B,Point C){//给予三个点,求圆心。
    double a = 2*(B.x - A.x);
    double b = 2*(B.y - A.y);
    double c = (B.x*B.x+B.y*B.y) - (A.x*A.x+A.y*A.y);
    double d = 2*(C.x-B.x);
    double e = 2*(C.y-B.y);
    double f = (C.x*C.x + C.y*C.y) - (B.x*B.x + B.y*B.y);
    double x = (b*f-e*c)/(b*d-e*a);
    double y = (d*c-a*f)/(b*d-e*a);
    double r = sqrt((x-A.x)*(x-A.x) + (y-A.y)*(y-A.y));
    Point ans(x,y);
    R = r;
    return ans;
}

对于一个水平的数轴,其上有N个点找到一个点使其距离和最小,那么这个点是中位数那个点。。

如图这里写图片描述
无论是奇数和点还是偶数个点,都相当于是两两配对。这种肯定是最佳的。注意千万不要误认为是平均值的点是最小的。应为选平均值,除非平均值是中位数,否则一定会在两两配对的基础上多个点到平均值的距离。可以画图看下。注意!~!
参考题:http://acm.henu.edu.cn/problem/problempage?id=1013

乘积最大定理:
把一个数拆分成多个不同的数相加,求他们的成绩最大值时,把这个数拆成从2开始的多个连续的数得到的乘积是最大的。

例题:http://acm.hdu.edu.cn/showproblem.php?pid=5976

组合数恒等公式
C n m = C n − 1 m + C n − 1 m − 1 C_{n}^{m} = C_{n-1}^{m} + C_{n-1}^{m-1} Cnm=Cn1m+Cn1m1
利用这个公式可以对组合数进行打表
代码如下:

const int MAX = 3010;
typedef long long ll;
ll C[MAX][MAX];
void init(){
    for(int i=0;i<=3000;++i){
        C[i][0] = 1;
        for(int j=1;j<=i;++j){
            C[i][j] = C[i-1][j] + C[i-1][j-1];
        }
    }
}

海伦公式求三角形面积:
p ( p − a ) ( p − b ) ( p − c ) 2 \sqrt[2]{p(p-a)(p-b)(p-c)} 2p(pa)(pb)(pc)
其中p为半周长,a,b,c为三边的周长。

求正多边形的面积
因为是正多边形,所以我们可以通过把正N多边形分成N个等腰三角形。求出每个等腰三角形的面积,再乘以N即可。
首先我们可以求出 θ = P I / N θ = PI/N θ=PI/N
这样 R = ( a / 2 ) / s i n ( θ ) R = (a/2)/sin(θ) R=(a/2)/sin(θ)
即等腰三角形的高也可以求出 h = R ∗ c o s ( θ ) h = R*cos(θ) h=Rcos(θ)
故正多边形的总面积也可以算出 S = ( a ∗ h ) / 2 ∗ N S = (a*h)/2*N S=(ah)/2N
这里写图片描述
代码如下:

#include<bits/stdc++.h>

using namespace std;
const double PI = acos(-1.0);
double GetArea(int N,double A){
    double Deg = PI/N;
    double R = (A/2)/sin(Deg);
    double H = R*cos(Deg);
    double S = (A*H)/2*N;
    return S;
}

对于从N个数里面选2个数,求出最大的最小公倍数
在正整数中,任意两个数互素的概率是 6/(π^2) = 0.608.,对于随机生成数的情况,我们直接枚举最大的100个数就能得到正确结果。
例如:https://www.nowcoder.com/acm/contest/144/J

从N个数里面选任意个数相加 向M取模,问你有多少中结果?
求出N个数和M这个数的最大公约数GCD,M/GCD就是结果的总数。
因为N个数任意相加最后结果一定会说她们最大公约数的倍数,加M是因为加0就相当于加M。
两个题目:http://codeforces.com/contest/1011/problem/E
https://www.nowcoder.com/acm/contest/160/A

排列组合的一个性质:
C n m + C n m − 1 = C n + 1 m C_{n}^{m} + C_{n}^{m-1} = C_{n+1}^{m} Cnm+Cnm1=Cn+1m

对于N个线段覆盖的公共长度的求法
每个线段为l,r两个端点。那么N个线段的公共长度就是min® - max(l),即最小的右端点减去最大的左端点。如果为负数,表示不存在N个线段覆盖的端点。要注意思考啊。
参考题目:http://codeforces.com/contest/1029/problem/C

整除分块
∑ i = 1 n [ n i ] \sum_{i=1}^{n}[\frac{n}{i}] i=1n[in]
就是求这个表达式的和,[]表示向下取整.对于向下取整的除法是存在一个区间除以这个区间数,结果都相同。比如x/i = 2,那么x /2,就是得到2的区间最后一个数。所以我们可以利用这个性质。按区间分块计算。如下:

ll res = 0,r = 0;
    for(ll i=1;i<=x;i=r+1){
        r = x/(x/i);//获得这个区间的最后一个数
        res += (r-i+1)*(x/i);//用区间长度乘以结果
    }

参考题目:https://www.nowcoder.com/acm/contest/158/A

再给N个区间,求被N-1个区间覆盖的最大距离或者是点
最近两场cf都碰到这个问题,这里总结一下,考虑把所有左端点和右端点全部存起来,放到两个multiset里面,然后扫描N个区间,每次把两个端点删去。如果左端点的最大值比右端点的最小值下,那么这个区间就符合被N-1个区间覆盖。最后再把两个端点插入进去。维护最大值就可以了。
这个想法也可以推广到二维的情况。维护左右x,上下y,每次扫描删除四个端点。最后再判断对应x,y是否符合。再插入进去。
两个题目:
http://codeforces.com/contest/1029
http://codeforces.com/contest/1028/problem/C

在N大于2的时候,奇数的和和偶数的和的gcd一定是大于一的,而且是最中间的那个数,如果是偶数就是N/2
因为中间那个数相当于是一个中心对称轴,两边的对应位置的数的和一定是中间那个数的倍数。
参考题目:
http://codeforces.com/contest/1038/problem/B

如果有N个东西,每个东西出现的概率是p[i],那么出现东西的个数期望就是sum p[1-N]
我们可以假设有两个物品啊,出现概率分别是A,B,那么出现个数为0,1,2;
p[0] = (1-A)(1-B);
p[1] = A
(1-B)+(1-A)B = A-B+2AB
p[2] = AB
概率期望E = 0
p[0] + 1p[1] + 2p[2]
合并后E = A+B;
参考题目:https://www.nowcoder.com/acm/contest/180/B

对于B进制数,快速判断某一位的数是多少
对于一个B进制的数s,我们想知道第i位的数字是多少,那么
int num = (s%(pw[i]*B))/pw[i];
就可以求得这个位的数,先对其高一位取膜,再向下取整除以这一位的幂,即可得到这一位的数字。

一个常用的整数向上取整
c e i l ( ( d o u b l e ) s u m / N ) = ( s u m − 1 + N ) / N ceil((double)sum/N) = (sum-1+N)/N ceil((double)sum/N)=(sum1+N)/N
调用ceil需要转换成double,而后者可以直接在整数形式下向上取整.

gcd 辗转相减法 推广到求多个数
g c d ( x , y ) = g c d ( x − y , y ) gcd(x,y) = gcd(x-y,y) gcd(x,y)=gcd(xy,y)
对于多个数
g c d ( x , y , z ) = g c d ( x − y , y , z ) = g c d ( x − y , y − z , z ) gcd(x,y,z) = gcd(x-y,y,z) = gcd(x-y,y-z,z) gcd(x,y,z)=gcd(xy,y,z)=gcd(xy,yz,z)
参考例题:https://codeforces.com/problemset/problem/1458/A

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值