
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\n", ans[i]);
}
return 0;
}