【算法笔记】贪心 分治

1.关于几点声明:

虽然题目主要是贪心和分治,但是主要还是以分治为主,贪心的个别题目比较简单,可以忽略;为什么没有“福州集训day5”呢,因为那天讲数论,太快了所以导致听不懂;至于数据结构②,等这次结束以后慢慢写就好啦!吐舌头

2.分治—快速幂

题目是求a^b%p,其中数据很大,直接算的复杂度为O(b)一定超时,因此我们可以用分治法来求,复杂度是O(log n)。

①递归求快速幂

不难得出,当b为偶数时,a^b=a^b/2*a^b/2,那么我们吃要求除了a^1,从而平方得到a^4,在平方得到a^8,……,最后得到a^b.

当b为奇数的时候,a^b=a^b/2*a^b/2*b,那么球求法自然和b为偶数的情况一样。

代码如上,其中b=0和b=1为边界条件,res为最终结果。

②非递归法求快速幂

我们需要用到二进制的知识:以10为例,10=1010,,所以10=8+2=2^3+2^1,对应的二进制位是1和3,那么a^10=a^(2^3)*a(2*1)=a^8*a^2.

然后利用区这一性质即可求出快速幂.

long long power(long long a1,int b1,long long p1)
{
	int temp=b1;
	long long ans=1ll,s=a1%p1;
	while (temp)//当二进制没求完时
	{
		if (temp%2==1) ans=ans*s%p1;//二进制位为1时
		temp/=2;//求下一位二进制
		s=s*s%p1;
	}
	return ans;
}

2.归并排序求逆序对(分治法)

归并排序,只要将大序列分成两个小序列,然后逐个合并成大序列即可。

求逆序对:用分治法把序列分成两部分,假设要从小到大排序,党合并时:如果选择了右半部分的元素,表明左半部分剩余元素逗比右半部分的元素打,那么左半部分剩余元素和当前选择的元素均为逆序对。

注意:要看清if和else之间的配对。

3.灰常简单的贪心:

问题描述:

给定长度为N的字符串S要构造一个长度为N字符串TT是一个空串,反复执行下列任意操作:

S的头部删除一个字符,加到T的尾部;

S的尾部删除一个字符,加到T尾部;

目标是要构造字典序尽可能小的字符串T

思路:

两头字符一个大一个小 , 哪个 ?
!
一样大怎么办 ? BACDCB?
看第二个 !
第二 个也一样怎么办 ?
看第三个 !

考题题解:

1.输入a,b,n,p求c1*a^n-1+c2*a^n-2*b+c3*a^n-3*b^2……+cn*b^n-1。(这里的ci指的是杨辉三角形第行的第i项)

思路:二项式展开定理(好像是这样的),求的就是之前的power(a+b,n-1,p).

2.

clx还在幼儿园里的时候,老师曾经让个小朋友一起做一个游戏:
每个人会被分到一块牌子,上面写着一个数字.现在这个小朋友排成一队,手上的牌子就共同组成了一个数字.

现在clx想知道这个人怎么排队能够使得这个数字最大.

思路:

很多人都会想到用字典序排,其实这是错的,cmp排序函数如下:

bool cmp(string a,string b)
{
  return (a+b>b+a);
}


题目难懂,有解释哦!在上面,这个懂就好了。

思路:贪心+分治

贪心:尽可能拆分更多的3,若多1,则拆减个3乘4,若多个2,则乘上即可。

分治:求3的很多次方,用快速幂。

然后0和1特判即可

#include<bits/stdc++.h>
using namespace std;
long long power(int a1,int b1,int p1)
{
	int temp=b1;
	long long ans=1,s=a1%p1;
	while (temp)
	{
		if (temp%2==1) ans=((ans%p1)*(s%p1))%p1;
		temp/=2;
		s=s*s%p1;
	}
	return ans;
}
int main()
{
	freopen("pi.in","r",stdin);
	freopen("pi.out","w",stdout);
	int n;
	cin>>n;
	if (n==0) cout<<0;
	else if (n==1) cout<<1;
	else
	{
    	if (n%3==0) cout<<power(3,n/3,10000007);
    	if (n%3==1) cout<<(power(3,n/3-1,10000007)*4)%10000007;
    	if (n%3==2) cout<<(power(3,n/3,10000007)*2)%10000007;
    }
	fclose(stdin);
	fclose(stdout);
	return 0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值