【POJ3614】【USACO 2007 Nov Gold】 3.Sunscreen 贪心

题意:

有若干个区间,若干种数,每个数告诉你有多少个。

然后一个数可以被放到一个x∈该区间 的区间,问最多有多少个区间可以被放。

题解:

显然我们可以用二分图最大匹配做,水题。

但是此题有别的技巧、

就是我们可以贪心进行处理。

首先我们考虑到需要将两种数都排个序。

然后再进行贪心。

一种错误的贪心法是单调队列式贪心,就是记录个top,然后单调往后推。

这个不仔细想还不知道它是错的。

额,至于卡它的数据,,我可以提供给你一个错误代码和一个拍子,你们可以自己拍一组数据出来,很高效。

这里贴一份错误代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 3000
#define inf 0x3f3f3f3f
using namespace std;
int n,m,ans,i;
struct KSD
{
	int x,y;
	bool operator < (const KSD &a)const{return x==a.x?(y<a.y):(x<a.x);}
}cow[N],oil[N];
int main()
{
//  freopen("test.in","r",stdin);
	scanf("%d%d,",&n,&m);
	for(i=1;i<=n;i++)scanf("%d%d",&cow[i].x,&cow[i].y);
	for(i=1;i<=m;i++)scanf("%d%d",&oil[i].x,&oil[i].y);
	sort(cow+1,cow+n+1);
	sort(oil+1,oil+m+1);
	int top=1;
	for(i=1;i<=m;i++)
	{
		while(top<=n&&cow[top].y<oil[i].x)top++;
		while(top<=n&&oil[i].y&&cow[top].x<=oil[i].x)
		{
			if(oil[i].x<=cow[top].y)
			{
				oil[i].y--;
				ans++;
			}
			top++;
		}
	}
	printf("%d\n",ans);
	return 0;
}

这里贴一份数据生成器

#include <ctime>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 10
#define inf 0x3f3f3f3f
using namespace std;
int n,m;
int main()
{
	srand((unsigned)time(NULL));
	int i,j,k;
	int a,b,c;
	n=rand()%N+1;
	m=rand()%4+1;
	printf("%d %d\n",n,m);
	for(i=1;i<=n;i++)
	{
		a=rand()%N+1;
		b=rand()%N+a;
		printf("%d %d\n",a,b);
	}
	for(i=1;i<=m;i++)
	{
		a=rand()%(N*2)+1;
		b=rand()%3+1;
		printf("%d %d\n",a,b);
	}
	return 0;
}

这里贴个拍子

#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 3000
using namespace std;

int main()
{
	int i,g;
	system("g++ std.cpp -o std -g");
	system("g++ my.cpp -o my -g");
	system("g++ rand.cpp -o rand -g");
	for(g=1;g<=N;g++)
	{
		printf("Case %d :   ",g);
		system("rand>test.in");
		clock_t j=clock();
		system("my <test.in >my.out");
		clock_t k=clock();
		printf("my_use : %03dms  ",k-j);
		system("std <test.in >std.out");
		printf("std_use : %03dms  ",clock()-k);
		if(system("fc std.out my.out >NULL")==0){puts("result : AC");}
		else
		{
			puts("WAWAWAWAWAWAWAWA!!!!!!!!");
			system("start test.in");
			return 0;
		}
	}
	puts("");
	puts("****,please try again");
	return 0;
}

拿上述的东西,再找个标程就可以pai了。

下面说一下正确思路。

首先按照顺序我们可以知道哪些区间的下界满足条件,那么就只需要上界也满足条件就行了。

因为数递增,所以如果当前的某个可用区间的上界比当前数小,那么以后也不可能满足了,就可以弹出去。

这样通过优先队列可以得到一个上界满足且最小的区间,这个区间则可以被计入答案。

思想说了个大概,没懂就看代码吧。

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 3000
#define inf 0x3f3f3f3f
using namespace std;
int n,m,ans,i;
priority_queue<int>pq;
struct KSD
{
	int x,y;
	bool operator < (const KSD &a)const{return x==a.x?(y<a.y):(x<a.x);}
}cow[N],oil[N];
int main()
{
//	freopen("test.in","r",stdin);
	scanf("%d%d,",&n,&m);
	for(i=1;i<=n;i++)scanf("%d%d",&cow[i].x,&cow[i].y);
	for(i=1;i<=m;i++)scanf("%d%d",&oil[i].x,&oil[i].y);
	sort(cow+1,cow+n+1);
	sort(oil+1,oil+m+1);
	int top=1;
	for(i=1;i<=m;i++)
	{
		while(top<=n&&cow[top].x<=oil[i].x)
			pq.push(-1*cow[top++].y);
		while(!pq.empty()&&oil[i].y)
		{
			int ttt=pq.top();
			if((-1*ttt)>=oil[i].x)ans++,oil[i].y--;
			pq.pop();
		}
	}
	printf("%d\n",ans);
	return 0;
}
时间: 2024-10-15 15:17:23

【POJ3614】【USACO 2007 Nov Gold】 3.Sunscreen 贪心的相关文章

【POJ3612】【USACO 2007 Nov Gold 】1.Telephone Wire 动规

题意: 给出若干棵树的高度,你可以进行一种操作:把某棵树增高h,花费为h*h. 操作完成后连线,两棵树间花费为高度差*定值c. 求两种花费加和最小值. 题解: 跟NOIP2014 D1T3很像. 暴力动规是O(1*10^9)会T 所以单调队列一下,每颗树扫两遍结束. 完事,看水代码吧. #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define N

【POJ3613】【USACO 2007 Nov Gold】 2.Cow Relays 矩阵乘法?

题意:给你一个m条边的图,求s到t的正好用k条边的最短路. (输入k,t,s,t) 题解: 先说说暴力. 动规f[k][i][j]表示i到j经过k条边的最短路,然后外层循环k一遍遍跑最后出解. 显然大概率T. 然后有一种思路: 我们可以动规求得f[k][i][j]表示i到j经过k条边的最短路,然后再求g[i]表示从终点走i步回到终点的最短路. 这样我们就可以乱搞过了.(没写,也没细想) 再之后是正解: 我们可以利用类似于快速幂的方法求f[i][j]表示i到j正好用多少多少步. 然后思想是使用边数

【POJ3612】【USACO 2007 Nov Gold】 1.Telephone Wire 动态调节

意甲冠军: 一些树高给出.行一种操作:把某棵树增高h,花费为h*h. 操作完毕后连线,两棵树间花费为高度差*定值c. 求两种花费加和最小值. 题解: 跟NOIP2014 D1T3非常像. 暴力动规是O(1*10^9)会T 所以单调队列一下,每颗树扫两遍结束. 完事,看水代码吧. #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define N 101

【BZOJ1229】【USACO 2008 Nov Gold】 4.Toys sadstory 三分+贪心

sad story:我们自己oj的数据貌似有点问题.标程WA了5% 题解: 复制去Google翻译翻译结果 首先引一下VFK神犇的证明来证明一下这道题是三分.. { 我来告诉你世界的真相 = = 因为这题能最小费用最大流 每次最短路长度不降 所以是单峰的 最短路长度就是差分值.. 所以一阶导不降.. 是不是简单粗暴 你要证函数是单峰的. 当然是证斜率什么的 } 三分完初始买了多少个玩具,然后就是贪心. 首先我想说这个贪心真动规.虽然它真的是贪心. 首先先说一种错误的贪心. 就是从前往后扫,优先用

USACO 2007 NOV Sunscreen

题目 题目描述 To avoid unsightly burns while tanning, each of the C (1 ≤ C ≤ 2500) cows must cover her hide with sunscreen when they're at the beach. Cow i has a minimum and maximum SPF rating (1 ≤ minSPFi ≤ 1,000; minSPFi ≤ maxSPFi ≤ 1,000) that will work

【BZOJ】【1046】/【POJ】【3613】【USACO 2007 Nov】Cow Relays 奶牛接力跑

倍增+Floyd 题解:http://www.cnblogs.com/lmnx/archive/2012/05/03/2481217.html 神题啊= =Floyd真是博大精深…… 题目大意为求S到E,恰好经过N条边的最短路径(姑且称为路径吧,虽然好像已经不是了……) 总共只有大约200个点(很多点根本没走到,离散化一下即可)所以可以考虑Floyd算最短路. 引用下题解: 题目求i,j之间边数恰为N的最短路径(边可以重复走),我们知道线性代数中有:01邻接矩阵A的K次方C=A^K,C[i][j

[USACO 2009 Feb Gold] Fair Shuttle (贪心+优先队列)

题目大意:有N个站点的轻轨站,有一个容量为C的列车起点在1号站点,终点在N号站点,有K组牛群,每组数量为Mi(1≤Mi≤N),行程起点和终点分别为Si和Ei(1≤Si<Ei≤N).计算最多有多少头牛可以搭乘轻轨. 一道经典的贪心题目,每当一头牛上车的时候,如果超载,我们就优先踢出去行程终点比较远的那部分牛 而 踢出哪些行程终点较远的牛 以及 哪些在车上的牛在这站到达了终点,都可以用优先队列来维护,复杂度约为 贴上代码: 1 #include <cstdio> 2 #include <

奶牛接力 (Cow Relays, USACO 2007 Nov)

题目描述 For their physical fitness program, N (2 ≤ N ≤ 1,000,000) cows have decided to run a relay race using the T (2 ≤ T ≤ 100) cow trails throughout the pasture. Each trail connects two different intersections (1 ≤ I1i ≤ 1,000; 1 ≤ I2i ≤ 1,000), each

【USACO 2008 Nov Gold】 1.Mixed Up Cows 状压DP、

题解: 首先考虑dfs,但是看到答案的"64bit"就放弃了吧. 所以肯定是组合数.状压DP什么的,尤其是那个16,标准的状压数. 好吧,就是状压DP. f[i][j]表示i是状压的01串表示哪个取了哪个没取,然后j是结尾字符, 虽然水,但是时间复杂度是可以过的. 代码: #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include &