To_Heart—总结——所学知识总结

前言

为了完成自己立下的flag,笔者决定开一篇博客,将自己所学过的所有板块进行梳理,也许工程量有些浩大,但笔者相信,自己一定可以成功。

基本算法

贪心

通过局部最优解构成全局最优解

例题

均分纸牌

题解

纸牌总数是一定的,把牌堆看成一个序列,每个堆最后的纸牌数都应该是这个序列的平均数。所以就统计那些牌堆不为平均数即可。

#include<bits/stdc++.h>
using namespace std;

int a[105],sum;

int main(){
    
    
	int n;
	cin>>n;
	for(int i=1;i<=n;i++){
    
    
		scanf("%d",&a[i]);
		sum+=a[i];
	}
	sum/=n;
	for(int i=1;i<=n;i++){
    
    
		a[i]-=sum;
	}
	sum=0;
	for(int i=1;i<=n;i++){
    
    
		if(!a[i])
			continue;
		a[i+1]+=a[i];
		sum++;
	}
	cout<<sum;
	return 0;
}

二分查找

首先,放句名言

90%的程序员无法正确实现二分查找算法

二分主要利用了序列的单调性。假设一个单调递增的序列,那么其中的任何一个元素都比前面的所有元素大,都比往后的所有元素小。所以我们可以折半查找某一元素

二分可以在O(logn)的复杂度中查找序列的某一元素。

模板

int l=0,r=n+1,ans=0;
while(l<=r){
    
    
	int mid=(l+r)>>1;
	if(/*自己写条件*/)
		l=mid-1,ans=mid;
	else
		r=mid+1;
}

搜索

不会吧,不会吧,不会真的有人连搜索都打不来吧

DP

不会吧,不会吧,不会真的有人连DP都会打吧

因为搜索和DP的知识太多了,所以笔者就单独把它们列出来。

前缀和

前缀和可以用O(n)的时间复杂度对数组进行预处理,然后再O(1)的时间之类求出任意两个元素之间的元素和。

我们可以用一个数组sum来计算前缀和,其中 s u m i sum_i sumi表示前i项的元素和。

所以很容易可以得到: s u m i = s u m i − 1 + a i sum_i=sum_{i-1}+a_i sumi=sumi1+ai ,其中 a i a_i ai表示当前元素的值。

如果我们要查找第i项到第j项的前缀和,就可以看成求 1 ∼ j 1 \sim j 1j项的前缀和再减去 1 ∼ i − 1 1 \sim i-1 1i1项的前缀和,所以就可以表示成 s u m i − s u m j − 1 sum_i-sum_{j-1} sumisumj1

数据结构

并查集

可以在log的时间复杂度中判断出两个元素是否在一个集合。

具体实现可以参考这篇博客

当然,我还是要提一提

现在假设有一堆不同的元素,每几个元素就组成一个集合。

我们在每一个集合当中选出一个元素作为代表,那么只要两个元素所在集合的代表相同,它们就在同一个集合里面。

那如果我们想把两个不同的集合合成一个集合怎么办呢?

很简单,只要将其中一个集合的代表放在另一个集合之中就可以了

模板如下

首先是初始化

void Make_Set(int n){
    
    
	for(int i=1;i<=n;i++){
    
    
		pre[i]=i;
	}
}

然后是查集

int Find(int x){
    
    
	if(pre[x]!=x)
		pre[x]=Find(pre[x]);
	return pre[x];
}

最后是并集

void Join(int x,int y){
    
    
	int fx=Find(x),fy=Find(fy);
	if(fx!=fy)
		pre[fx]=fy;
}

线段树

线段树和下文将提到的树状数组一样,是解决区间问题的数据结构,但线段树可以实现的功能比树状数组多。

因为牵扯的东西有点多,所以就又开了一篇博客,这里就不展示了。

树状数组

吖,这个东西不好讲
那我们又开一篇博客吧!!!
绝对不是因为我想水博客

DP

线性DP

后面的有时间再写吧。。。

猜你喜欢

转载自blog.csdn.net/xf2056188203/article/details/113835626