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字符串T。T是一个空串,反复执行下列任意操作:
l 从S的头部删除一个字符,加到T的尾部;
l 从S的尾部删除一个字符,加到T的尾部;
目标是要构造字典序尽可能小的字符串T
思路:
考题题解:
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;
}