Problem 2136 取糖果
Accept: 89 Submit: 221
Time Limit: 1000 mSec Memory Limit : 32768 KB
Problem Description
有N个袋子放成一排,每个袋子里有一定数量的糖果,lzs会随机选择连续的几个袋子,然后拿走这些袋子中包含最多糖果的袋子。现问你,在选择x个袋子的情况下,lzs最坏情况下,也就是最少会拿到多少个糖果?对于x取值为1到n都分别输出答案。
Input
第一行一个整数T,表示有T组数据。
每组数据先输入一行一个整数N(1<=N<=100000),表示袋子数,接下来一行输入N个正整数,输入的第i个数表示第i个袋子所装的糖果数。
Output
每组数据输出n行,第i行表示lzs随机取连续的i个袋子时的最坏情况下能拿到的糖果数。
Sample Input
1
5
1 3 2 4 5
Sample Output
1
3
3
4
5
在众神题解的关照下,终于想通且A了。
算法:①按元素值从小到大依次求出每个元素所在的连续最长区间长度,使该元素在这个区间内最大,②然后因为是枚举每个元素的最长区间长度的,需要ans[len]=min(ans[len], ans[len+1]).
第②步的正确性?
1.当len=1时,则ans[1] = min(e[i]),i从0,到n-1,e[i]为第i个元素;
2.当len=n时,则ans[n] = max(e[i]), 同上;
3.当len取其它值设为k,若某个元素可达区间长度为bk,且bk>k, 则该元素一定是某些(个)区间长度为k的区间内最大值, 所以ans[k] =min(ans[i]) 对所有大于k的i。
ACCEPTED:
#include<cstdio> #include<iostream> #include<algorithm> using namespace std; const int maxn = 111111; const int inf = 1 << 30; int lft[maxn], rit[maxn]; int e[maxn], ind[maxn], n; int lcnt[maxn], rcnt[maxn]; //模拟双向链表 int ans[maxn]; bool cmp(const int a, const int b){ return e[a] < e[b]; } int main(){ int t; scanf(" %d", &t); while(t--){ scanf(" %d", &n); for(int i=0; i<n; i++){ scanf(" %d", e+i); ind[i]=i; //左右元素下标 lft[i] = i-1; rit[i] = i+1; //计算连续区间长度,左边,右边 lcnt[i] = rcnt[i] = 0; ans[i+1] = inf; } //升序排,第i大的元素在ind[i] sort(ind, ind+n, cmp); for(int i=0; i<n; i++){ int tind = ind[i], tlen = rcnt[tind] + lcnt[tind] + 1; ans[tlen] = min(ans[tlen], e[tind]); //删除e[i], 更新左右元素区间长度 if(lft[tind]>-1) rcnt[lft[tind]]+=(rcnt[tind]+1), rit[lft[tind]] = rit[tind]; if(rit[tind]<n) lcnt[rit[tind]]+=(lcnt[tind]+1), lft[rit[tind]] = lft[tind]; } //... for(int i=n-1; i; i--) ans[i]=min(ans[i], ans[i+1]); for(int i=1; i<n+1; i++) printf("%d ", ans[i]); } return 0; }