LOJ 一本通提高篇1.1贪心算法 练习

复习时食用,会比较简略。


目录

#10005. 「一本通 1.1 练习 1」数列极差

#10006. 「一本通 1.1 练习 2」数列分段

#10007. 「一本通 1.1 练习 3」线段

#10008. 「一本通 1.1 练习 4」家庭作业

#10009. 「一本通 1.1 练习 5」钓鱼

#10010. 「一本通 1.1 练习 6」糖果传递


#10005. 「一本通 1.1 练习 1」数列极差

题目

题目大意

一个由n个正整数组成的数列,每次擦去其中的两个数a和b。

然后在数列中加入一个数a*b+1,直至剩下一个数为止。

按这种操作方式最后得到的数中,最大的为max,最小的为min。

该数列的极差定义为M=max-min。

请对于给定的数列计算出相应的极差M。

对于全部数据,0<=n<=50000,保证所有数据计算均在32位有符号整数范围内。

题目分析

surprise!神奇的规律!

要得到max每次就擦掉最大的两个,要得到min每次就擦掉最小的两个。

进行多次试验寻找普遍规律。

肯定有什么证明方法,看我脑筋急转弯。还是不会。

代码

#include
#include
#include
using namespace std;

int n,nn,x,a[50010],b[50010];
int cmp(int x,int y) { return x>y; }

int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&x);
		a[i]=b[i]=x;
	}
	scanf("%d",&x);
	
	sort(a+1,a+1+n,cmp); nn=n;
	for(int i=1;i<=n-1;i++)//每次檫最大
	{
		a[1]=a[1]*a[2]+1;
		a[2]=a[nn]; nn--;
		sort(a+1,a+1+nn,cmp);
	}
	
	sort(b+1,b+1+n); nn=n;
	for(int i=1;i<=n-1;i++)//每次擦最小
	{
		b[1]=b[1]*b[2]+1;
		b[2]=b[nn]; nn--;
		sort(b+1,b+1+nn);
	}
	printf("%d",b[1]-a[1]);
	return 0;
}

 

#10006. 「一本通 1.1 练习 2」数列分段

题目

题目大意

给定的一个长度为N的正整数数列A_i。

将其分成连续的若干段,使每段和不超过M,问最少能将其分成多少段。

对于20%的数据,有n<=10;

对于40%的数据,有n<=1000;

对于100%的数据,有n<=10^5,m<=10^9大于所有数的最大值。

题目分析

好水。

不懂就看代码ba。

代码

#include
#include
#include
using namespace std;

int main()
{
	int n,m; scanf("%d%d",&n,&m);
	int s=0,ans=0;
	for(int i=1;i<=n;i++)
	{
		int x; scanf("%d",&x); s+=x;
		if(s>m) { ans++; s=x; }//超过了
	}
	if(s) ans++;
	printf("%d",ans);
	return 0;
}

 

#10007. 「一本通 1.1 练习 3」线段

题目

题目大意

有n条线段,选取其中k条线段使这k条线段没有重合部分,问k最大为多少。

对于20%的数据,n<=10;

对于50%的数据,n<=10^3;

对于70%的数据,n<=10^5;

对于100%的数据,n<=10^6,0<=ai

题目分析

回归例题1、2???

一段时间改成了一条线段。

一样要需要没有重合。

报告完毕。

代码

#include
#include
#include
using namespace std;

struct node{int a,b;}a[1000010];
int cmp(node x,node y) { return x.b=end)
		{
			ans++; end=a[i].b;
		}
	}
	printf("%d",ans);
	return 0;
}

 

#10008. 「一本通 1.1 练习 4」家庭作业

题目

题目大意

每个作业完成时间都是一天,在规定的时间内交上来的话才有学分。

找到一个完成作业的顺序获得最大学分。

对于20%的数据,n<=10^3;

对于40%的数据,n<=10^4;

对于60%的数据,n<=10^5;

对于100%的数据,n<=10^6,作业的完成期限均小于7*10^5

题目分析

回归例题5。

只要加一个小小小优化就好了。

而且这个优化很容易懂。

kk判断i和i之前的时间是否被填满,若已经填满了就不要去找了。

代码

#include
#include
#include
using namespace std;

bool f[700010],kk[700010];
struct node{int time,money;}a[1000010];
int cmp(node x,node y) { return x.money>y.money; }

int main()
{
	int n; scanf("%d",&n);
	memset(f,false,sizeof(f));
	memset(kk,false,sizeof(kk));
	for(int i=1;i<=n;i++) scanf("%d%d",&a[i].time,&a[i].money);
	sort(a+1,a+1+n,cmp);
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		bool k=false;
		for(int j=a[i].time;j>=1;j--)
		{
			if(kk[j]) break;
			if(!f[j]) { f[j]=true; k=true; }
			if(k) break;
		}
		if(k) ans+=a[i].money;
		else kk[a[i].time]=true;
	}
	printf("%d",ans);
	return 0;
}

 

#10009. 「一本通 1.1 练习 5」钓鱼

题目

题目大意

有n个钓鱼湖,从左到右编号为1,2,…,n。希望利用H个小时钓到更多的鱼。

从1出发,向右走,可选择在湖边停留一定的时间钓鱼,最后在某一个湖边结束钓鱼。

从第i个湖到第i+1个湖需要走5*T_i分钟,测出在第i个湖停留,第一个5分钟可以钓到F_i条鱼,以后再钓5分钟,钓到的鱼量减少D_i,若减少后的鱼量小于0,则鱼量为0。

没有其他因素影响钓到期望数量的鱼。求出最多能钓鱼的数量。

对于100%的数据,2<=n<=100,1<=h<=20。

题目分析

钓个鱼怎么这么多事。

枚举最远去到的鱼塘的位置,范围内的鱼塘任你挑,当然是钓最多的啊。

很好懂的吧。好暴力啊。

我果然还是太辣鸡了,如果鱼的数量是负的就不要钓了,傻吗还钓。

我才不会告诉你我小测的时候就错在这。

代码

#include
#include
#include
using namespace std;

bool f=false;
int n,h,s,t[110],ans=0;
struct node{int a,b;}a[110],b[110];
int cmp(node x,node y) { return x.a>y.a; }

int main()
{
	scanf("%d%d",&n,&h);
	for(int i=1;i<=n;i++) scanf("%d",&a[i].a);
	for(int i=1;i<=n;i++) scanf("%d",&a[i].b);
	h*=12; t[1]=0; s=n;//12个五分钟
	for(int i=2;i<=n;i++)
	{
		int x; scanf("%d",&x);
		t[i]=t[i-1]+x;//x个五分钟
		if(!f&&t[i]>=h) f=true,s=i-1;//s表示最远能去到的鱼塘 
	}
	for(int ed=1;ed<=s;ed++)
	{
		for(int i=1;i<=ed;i++) b[i]=a[i];
		int tt=h-t[ed],kk=0;
		while(tt--)//实在是很暴力了 
		{
			sort(b+1,b+1+ed,cmp);
			if(b[1].a<=0) break;
			kk+=b[1].a; b[1].a-=b[1].b;
		}
		ans=max(ans,kk);
	}
	printf("%d",ans);
	return 0;
}

 

#10010. 「一本通 1.1 练习 6」糖果传递

这道题已经尽我的洪荒之力写的详细了!!!(个人觉得很明白了昂)

你可能感兴趣的:(loj,贪心)