【WOJ 2576】小咸鱼,大梦想

【题目】

题目描述:

n n 条咸鱼,每条咸鱼都有自己的能力值 a i a_i ,现在你要给这些咸鱼送饭,当然咸鱼也有梦想,他们会暗中较劲,所以你给每个咸鱼送饭的时候要保证对于相邻的两条咸鱼,能力值大的咸鱼得到的饭要比咸鱼值少的多,请问最少送多少饭就能满足条件?

输入格式:

一开始是一个数字 t t ,表示数据组数

接下来 t t 行,每行是一个数 n n ,表示咸鱼的数量

接下来一行有 n n 个数,表示每个咸鱼的能力值

输出格式:

对于每组数据,输出答案

样例数据:

输入
2
3
1 2 3
4
3 1 2 2

输出
6
6

提示:

【样例解释】
第一个样例中第 1 1 个咸鱼送 1 1 份饭,第 2 2 个咸鱼送 2 2 份饭,第 3 3 个咸鱼送 3 3 份饭。

第二个样例中第 1 1 个咸鱼送 2 2 份饭,第 2 2 个咸鱼送 1 1 份饭,第 3 3 个咸鱼送 2 2 份饭,最后一个咸鱼送 1 1 份饭,因为最后两个咸鱼的能力值不是严格大于。

【数据范围】
30 % 30 \% 的数据保证 t t 10 10 n n 1000 1000
100 % 100 \% 的数据保证 t t 10 10 n n 100000 100000 0 0 a i a_i 1 0 9 10^9


【分析】

其实也不是一道难题,只是有一个细节错了,就 Wa 了很久。。。

对于一个点 i i ,其实只用比较和 i 1 i-1 的关系就可以了(因为 i i i + 1 i+1 的情况会在 i + 1 i+1 的时候被算到)

比较的时候, a a 小的往大的连边,就表示能力大的要多吃点

记录 f i f_i 表示 i i 要多少饭,那么在拓扑排序的时候,直接更新就行了


【代码】

#include<stack>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
using namespace std;
int n,t,tot;
int a[N],f[N],in[N];
int first[N],v[N],nxt[N];
void init()
{
	tot=0;
	memset(f,0,sizeof(f));
	memset(in,0,sizeof(in));
	memset(first,0,sizeof(first));
}
void add(int x,int y)
{
	tot++;
	nxt[tot]=first[x];
	first[x]=tot;
	v[tot]=y;
}
void Topology()
{
	int x,i;
	stack<int>sta;
	for(i=1;i<=n;++i)
	  if(!in[i])
	    f[i]=1,sta.push(i);
	while(!sta.empty())
	{
		x=sta.top();sta.pop();
		for(i=first[x];i;i=nxt[i])
		{
			in[v[i]]--;
			f[v[i]]=max(f[v[i]],f[x]+1);
			if(!in[v[i]])  sta.push(v[i]);
		}
	}
}
int main()
{
	int i;
	scanf("%d",&t);
	while(t--)
	{
		init();
		scanf("%d",&n);
		scanf("%d",&a[1]);
		for(i=2;i<=n;++i)
		{
			scanf("%d",&a[i]);
			if(a[i]>a[i-1])  add(i-1,i),in[i]++;
			if(a[i]<a[i-1])  add(i,i-1),in[i-1]++;
		}
		Topology();
		long long ans=0;
		for(i=1;i<=n;++i)
		  ans+=f[i];
		printf("%lld\n",ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/forever_dreams/article/details/83505518
今日推荐