这些东西就是放在一起讲。贪心分治是一种策略,相对模拟需要更多的思维。老师昨天讲的都是基本的贪心分治。
贪心
T1 [usaco 2009 dec]游荡的奶牛
题目描述】奶牛要吃草,但是都很自私,不愿意和别的牛共享自己的草地。输入每头牛吃草范围的左端点和右端点,计算最多可以有几头牛一起吃草。
题解】输入时按照左端点和右端点输入结构体。之后按照右端点排序。排完序后,第一头牛一定可以吃草。在一一判断,如果这一头牛与前面确定能吃草的牛的范围不会重叠,这头牛就可以吃草。
具体代码如下:
#include<bits/stdc++.h>
using namespace std;
int n;
int now,ans=1;
struct hh
{
long long e,s;
}a[50050];
bool mycmp(hh x,hh y)//按照右端点排序
{
return (x.s<y.s);
}
int main()
{
cin>>n;
for (int i=1;i<=n;i++) cin>>a[i].e>>a[i].s;
sort (a+1,a+n+1,mycmp);
now=1;
for (int i=2;i<=n;i++)
if (a[i].e>=a[now].s)//判断范围是否重叠的条件,如果i的左端点大于now的右端点时,说明它们的范围不会重合
{
ans++;
now=i;
}
cout<<ans<<endl;
return 0;
}
==========================================
T2三值排序
题目描述】输入一个只包含1,2,3的序列。问至少要交换几次才能变为一个从小到大排列的序列。
题解】在输入时记录1,2,3出现的数量。设1出现a次,2出现b次,3出现c次。所以在第一位到第a位是排完以后1的位子,在a+1到a+b的是拍完以后2的位子,剩下的是3的位子。当在1的位子发现2 时,到2的位子找1,与2交换位子,在1的位子发现3时,去3的位子找1,并与在1 的位子的3交换位置。当1都回到自己的位子是,开始改变2。在2找到一个3,说明需要一次交换,所以要将交换顺序++;
代码如下:
#include<bits/stdc++.h>
using namespace std;
int n,ans=0;
int x=0,y=0,z=0;
int a[1100];
int m;
int l;
int main()
{
cin>>n;
for (int i=1;i<=n;i++) //输入并累加
{
cin>>a[i];
if (a[i]==1) x++;
if (a[i]==2) y++;
if (a[i]==3) z++;
}
m=x+1;//2 的起始位子
l=n;
for (int i=1;i<=x;i++)//在1 的位子寻找2 和 3。
if (a[i]!=1)
{
if (a[i]==2)//等于二,与二交换
{
for (;a[m]!=1;m++);
int t=a[i];a[i]=a[m];a[m]=t;
ans++;
}
if (a[i]==3)//等于三,与三交换
{
for (;a[l]!=1;l--);
int t=a[i];a[i]=a[l];a[l]=t;
ans++;
}
}
for (int i=x+1;i<=x+y;i++)//在二的位子找三。如果不是二就++。
if (a[i]!=2) ans++;
cout<<ans<<endl;
return 0;
}
分治
比赛安排
题目描述】
选手进行循环比赛,要求每名选手要与其他选手都赛一次,每名选手每天比赛一次,要求每天没有选手轮空。
题解】
找
规
律
从八位选手的循环比赛表中可以看出,这是一个具有对称性的方阵,可以把方阵一分为四来看,那么左上角的4*4的方阵就是前四位选手的循环比赛表,而右上角的4*4的方阵就是后四位选手的循环比赛表,它们在本质上是一样的,都是4个选手的循环比赛表,所不同的只是选手编号不同而已,将左上角中方阵的所有元素加上4就能得到右上角的方阵.下方的两个方阵表示前四位选手和后四位选手进行交叉循环比赛的情况,同样具有对称性,将右上角方阵复制到左下角即得到1,2,3,4四位选手和5,6,7,8四位选手的循环比赛表,根据对称性, 右下角的方阵应与左上角的方阵相同.这样,八名选手的循环比赛表可以由四名选手的循环比赛表根据对称性生成出来.同样地, 四名选手的循环比赛表可以由二名选手的循环比赛表根据对称性生成出来,而两名选手的循环比赛表可以说是已知的。
代码如下:
#include<bits/stdc++.h>
const int MAXN=33,MAXM=5;
int matchlist[MAXN][MAXN];
int m;
int main()
{
scanf("%d",&m);
int n=1<<m,k=1,half=1; // 1<<m 相当于 2^m
matchlist[0][0]=1;
while (k<=m)
{
for (int i=0;i<half;i++) //构造右上方方阵
for (int j=0;j<half;j++)
matchlist[i][j+half]=matchlist[i][j]+half;
for (int i=0;i<half;i++) //对称交换构造下半部分方阵
for (int j=0;j<half;j++)
{
matchlist[i+half][j]=matchlist[i][j+half];
//左下方方阵等于右上方方阵
matchlist[i+half][j+half]=matchlist[i][j];
//右下方方阵等于左上方方阵
}
==============================================
T2高级模运算
题目描述】不管故事背景的话就是求Ai^Bi。并输出他们的结果mod m 的结果
题解】其实就是快速幂,在每次算完后就做模运算。
代码如下:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int m,h;
long long ans=0;
long long x,y;
long long t,s;
cin>>m>>h;
for (int i=1;i<=h;i++)
{
cin>>x>>y;
t=y,s=x;
long long Ans=1;
while (t!=0)
{
if (t%2==1)
Ans=Ans*s%m;
t/=2;
s=s*s%m;
}
ans=ans+Ans%m;
}
cout<<ans%m<<endl;
return 0;
}
快速幂的性质
(a+b+c) %k= ( (a+b)%k+c)%k
(a-b-c) %k= (a-b)%k -c
(a*b*c) %k =a*b %k *c %k