ACM之近期学习总结

博主总结了最近ACM学习的数据结构,包括栈、队列、树及二叉树、堆,还提及了相关概念。此外,总结了前缀和、计算几何、贪心等问题的题意与思路,以及用反三角函数求圆周率的两种高精度方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先来总结一下最近所学。最近ACM学了数据结构:栈,队列,树及二叉树,堆。但只是对这几项概念的基本了解。具体在题目中应用到的数据结构知识还需自己以后多做题多学习多总结。最近自己也做了二分用法的题,同时还做了一些琐碎的题,接下来总结一下具体的知识点。

一. 栈

  • 栈是只能在某一端插入和删除的特殊线性表。(底端封闭)
  • 进行删除和插入的一端称栈顶,另一堆称栈底。插入一般称为进栈(push),删除则称为退栈(pop)。
  • 栈也称为后进先出表(LIFO表)
  • 一个栈可以用定长为N的数组S来表示,用一个栈指针TOP指向栈顶。若TOP=0,表示栈空,TOP=N时栈满。进栈时TOP加1。退栈时TOP减1。当TOP<0时为下溢。栈指针在运算中永远指向栈顶。

 

 

二.  队列

 

  •    队列是限定在一端进行插入,另一端进行删除特殊线性表。
  •    队列的删除和插入分别称为出队和入队。允许出队的一端称为队头,允许入队的一端称为队尾。 由于总是先入队的元素先 出队(先排队的人先买完东西),这种表也称为先进先出(FIFO)表。
  •     队列可以用数组Q[m+1]来存储,数组的上界m即是队列所容许的最大容量。在队列的运算中需设两个指针:

        head:队头指针,指向实际队头元素的前一个位置
        tail:队尾指针,指向实际队尾元素所在的位置

 

三. 树及二叉树

  • 在二叉树的第i层上最多有2^(i-1)个结点(i>=1)
  • 深度为k的二叉树至多有2^k –1个结点(k>=1)
  • 一棵深度为k且有2k–1个结点的二叉树称为满二叉树
  • 对任意一棵二叉树,如果其叶结点数为n0,度为2的结点数为n2,则一定满足:n0=n2+1
  • 具有n个结点的完全二叉树的深度为floor(log2n)+1

 

 

四. 堆 (应用于优先队列)

 

  • 堆结构是一种数组对象,它可以被视为一棵完全二叉树。树中每个结点与数组中存放该结点中值的那个元素相对应
  • 堆具有这样一个性质,对除根以外的每个结点i,A[parent(i)]≥A[i]。这种堆又称为“大根堆”;反之,对除根以外的每个结点i,A[parent(i)]≤A[i]的堆,称为“小根堆”

 

闲碎知识点总结:

一.  前缀和问题

题意:在长达n分钟的讲座中,每分钟老师会讲ai个知识点,Mishka每分钟有一个状态,1表示清醒,可以将当前的知识点全部记下,0表示睡觉,不能记知识点,你有一个神奇的药水,可以让她连续k分钟保持清醒,求Mishka记下的最大知识点数量

思路:在所有连续的k区间里面,只需要找到在每个区间睡觉导致丢失的分数的最大值,那么就把这个方法用在此区间,这样就能保证最后所得的分数最大。

代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int a[maxn];
int t[maxn];
int pre[maxn];
int main()
{
    int n,k;
    int s=0;
    int temp=0;
    cin>>n>>k;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++)
    {
        cin>>t[i];
        if(t[i]) temp+=a[i];
    }
    memset(pre,0,sizeof(pre));
    pre[0]=0;
    for(int i=1;i<=n;i++)
    {
        if(t[i]) pre[i]=pre[i-1]+0;
        if(!t[i]) pre[i]=pre[i-1]+a[i];
    }
    for(int i=1;i<=n;i++)
    {
        s=max(s,(pre[i+k-1]-pre[i-1]));
    }
    s+=temp;
    cout<<s<<endl;
}

前缀和优化问题:

 

 用双重循环,用i来表示开始数,j表示结束的数,再通过一个数组来保存由i到j之间数的和,如:10 4 1,输入时的数组a[i]~a[j]之间的数相加,当i从1开始循环,j从m开始循环。循环比较到n-m+1,最后得出最小的和。 但我们可以用前缀和来优化。

 

  这个优化主要是用来在O(1)时间内求出一个序列a中,a[i]+a[i+1]+……+a[j]的和。

具体原理十分简单:用sum[i]表示(a[1]+a[2]+……+a[i]),其中sum[0]=0,则(a[i]+a[i+1]+……+a[j])即等于sum[j]-sum[i-1]

 

二.  计算几何问题

题意:

给你n个点,问你能否用两条直线,问你是否能用2条直线过所有点。

 
思路:

对于此题,当n<=4是一定成立的,n>4的时候我们可以任意取3个点,先以3点中的2点画一条直线,把该直线不能过的点存入vector中,再对剩下的所有点进行判断,它们是否都在一条直线上,是的话输出YES,不是则取3点中其他2点重复进行上步骤,直到3种情况都没办法实现,那么可以输出NO了。

原理:若能用2条直线经过所有点,那么取任意三点中的某一条两点连线必然与其中一条直线重合
 

 

三.  贪心问题

题意:

给出你n个数,然后让你改变这个序列,找出满足要求的另外一个序列。要求是每个数两两之间互质,然后要求新的序列字典序要大于等于第一个序列,但是要求找出字典序最小。

思路:

任意一对数互质,可以通过标记其质因子来解决,在找到第一个违背互质的数时,只需要找出大于该数的最小的一个与前面所有数互质的数,在此之后,要想保证字典序最小,便是所有可用的质数从小向大取。

具体实现:

每次输入一个数,就找出这个数的所有因子,然后把它们的因子的倍数标记。注意:在此处要优化一下:比如标记过的因子的倍数就不用再标记了。如果你输入的这个数被标记过,那么你将要修改这个数,而且题目要求字典序要大于等于第一个序列,所以你就从这个数开始,遍历直到找出一个满足没有被标记的数字,然后把它这个位置赋值,接着还需要把最新找到的这个数的因子及其因子的倍数标记,这样我们就满足了大于等于字典序的要求了,接着后面的数,从2开始遍历,依次找到没有被标记的数,然后赋值,注意:你每次找到一个数,还是要标记它的因子即因子倍数。
 

 

四.  求圆周率精确度高的两种方法(用反三角函数)

一.用反三角函数表示圆周率的头文件

      #include <cmath>

二.用反三角函数表示的方法

I.    用反余弦函数表示

      const double pi=acos(-1.0);

      acos是反余弦函数,其功能是求反余弦。acos(-1.0)就是求-1.0的反余弦再赋值给double类型的常变量pi。而acos(-1.0) 的值就是圆周率pi.

II.   用反正切函数表示   

      const double pi = 4.0*atan(1.0);

     atan是反正切函数,其功能是求反正切。4.0*atan(1.0)就是求1.0的反正切乘以4再赋值给double类型的常变量pi。而atan(1.0) 的值就是1/4pi.则4.0*atan(1.0)就是圆周率pi.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值