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

智力大冲浪的数据加强版,n^2算法要被卡。

我们发现,原来的暴力代码最暴力的是这一段:
	for (register int j=num[i].pos; j>=1; --j) 
	if (!f[j]) 
	{
		f[j]=true,ans+=num[i].w;
		break;
	}
那么对于一个个往前找,直到找到一个空格子的这个步骤,能不能把它变成找1次就找到呢?
显然是不行的…但是log次,或a(n),即ackermaan,是可以的,所以就用一个并查集来维护每个格子前面第一个空格子是哪个格子。
#include <bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int n,xx,yy,ans;
int f[N];
struct number{int pos,w;}num[N];

inline bool cmp(number a,number b)
{
	return a.w>b.w;
}

int find(int x)
{
	if (f[x]==x) return x;
	return f[x]=find(f[x]);
}

int main(){
	scanf("%d",&n);
	for (register int i=1; i<=700000; ++i) f[i]=i;
	for (register int i=1; i<=n; ++i) scanf("%d%d",&num[i].pos,&num[i].w);
	sort(num+1,num+n+1,cmp); 
	for (register int i=1; i<=n; ++i)
	{
		xx=find(num[i].pos); 
		if (xx) 
		{
			ans+=num[i].w;
			yy=find(xx-1);
			f[xx]=yy;
		}
	}
	printf("%d\n",ans);
return 0;
}
还有一种思路,用一个大根堆来维护。
上一个代码可以理解为数据结构优化,而大根堆维护的思路就完全不同了。
从后往前进行扫描,如果发现有若干个pos为当前日期作业,就把它们的w放进大根堆中,然后每天可以完成一项作业,即每天可以从大根堆中取出堆顶元素,然后答案进行累加。如果在某些天堆中无元素了,即是题中的作业浪费情况了。
#include <bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int n,now,ans;
int f[N];
struct number{int pos,w;}num[N];

inline bool cmp(number a,number b)
{
	return a.pos<b.pos;
}

priority_queue<int>q;
int main(){
	scanf("%d",&n);
	for (register int i=1; i<=n; ++i) scanf("%d%d",&num[i].pos,&num[i].w);
	sort(num+1,num+n+1,cmp);
	now=n;
	for (register int i=700000; i>=1; --i)
	{
		while (now && num[now].pos>=i) q.push(num[now].w),now--;
		if (!q.size()) continue;
		ans+=q.top(); q.pop();
	}
	printf("%d\n",ans);
return 0;
}
发布了64 篇原创文章 · 获赞 29 · 访问量 672

猜你喜欢

转载自blog.csdn.net/Dove_xyh/article/details/103971156