[bzoj1345][Baltic2007]序列问题_单调栈
bzoj-1345 Baltic-2007 序列问题
题目大意:对于一个给定的序列a1,…,an,我们对它进行一个操作reduce(i),该操作将数列中的元素ai和ai+1用一个元素max(ai,ai+1)替代,这样得到一个比原来序列短的新序列。这一操作的代价是max(ai,ai+1)。进行n-1次该操作后,可以得到一个长度为1的序列。我们的任务是计算代价最小的reduce操作步骤,将给定的序列变成长度为1的序列。
数据范围:$1\le n\le 10^6$,$0\le a_i\le 10^9$。
想法:
这个题的考虑方法比较经典
就是对于每一个操作,把它按照某种规则分类。
然后分类之后比较好统计什么的。
像$CF1151E$一样的类型。
好,单独看这个题。
我们把每次合并当做一个小数被吃了。
所以我们就统计没个数被吃了那次的答案和即可。
假设$pre[i]$和$nxt[i]$分别表示第$i$个数前面比它大的第一个和后面比它大的第一个。
这个数一定是被前面的某个或者后面的某个吃掉。
如果这两个在当前数被吃掉之前被吃掉了,那一定没有当前数先被吃掉优。
故此我们用单调栈求出每个数前面第一个比它大的,和后面第一个比它大的。
每个数的答案就是$min(a_{pre_i},a_{nxt_i})$。
注意最大值没有贡献。
代码:
#include <bits/stdc++.h> #define inf (1 << 30) #define N 1000010 using namespace std; int a[N],q[N],pre[N],nxt[N]; typedef long long ll; ll ans=0; char *p1,*p2,buf[100000]; #define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++) int rd() {int x=0,f=1; char c=nc(); while(c<48) {if(c=='-') f=-1; c=nc();} while(c>47) x=(((x<<2)+x)<<1)+(c^48),c=nc(); return x*f;} int main() { int n=rd(); for(int i=1;i<=n;i++) a[i]=rd(); int top=0; for(int i=1;i<=n;i++) { while(top && a[i] > a[q[top]]) top -- ; pre[i] = q[top]; q[++top]=i; } top=0; for(int i=n;i;i--) { // printf("top : %d\n",top); while(top && a[i] > a[q[top]]) top -- ; nxt[i] = q[top]; q[++top]=i; } // for(int i=1;i<=n;i++) cout << pre[i] << ' ' << nxt[i] << endl ; a[0]=inf; for(int i=1;i<=n;i++) if(pre[i] || nxt[i]) ans += min(a[pre[i]],a[nxt[i]]); cout << ans << endl ; return 0; }
小结:这种解题方法比较独特,类型题好像也挺多的。看能不能想到吧。
| 欢迎来原网站坐坐! >原文链接<