【WOJ 2576】小咸鱼,大梦想

xiaoxiao2025-04-29  17

【题目】

题目描述:

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

输入格式:

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

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

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

输出格式:

对于每组数据,输出答案

样例数据:

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

输出 6 6

提示:

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

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

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

【分析】

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

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

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

记录 f i f_i fi 表示 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; }
转载请注明原文地址: https://www.6miu.com/read-5029422.html

最新回复(0)