【解题报告】洛谷P7726 天体探测仪
思路
对于排列中的一个数字 i ,设以 i 为区间最小值的最长的区间是 [li,ri]
首先考虑:如果已知 li,ri ,如何求出来 i 的具体位置
设 leni=ri−li+1 则对于某个 j≤leni 这段区间里面就一共有 leni−j+1 个长度为 j 的子区间,如果所有长度为 j 的区间中都包括 i ,那么 i 在 Sj 中就应该出现了 leni−j+1 次,反之,它在这个集合中的出现次数小于 leni−j+1 次
因此,我们可以找到最大的 j 使得 i 在 Sj 中出现的次数 ≤leni−j+1 次,那么 i 到区间边界的距离就是 j ,也就是说,i 到区间边界的距离就应该是 j ,也就是说, i 的位置就是 li+j 或者 ri−j
这两个位置是等价的,因为区间整体反转一下也不会对答案产生影响
我们发现上面的分析中只用到了 leni ,而 li,ri 仅仅用来定位,所以我们只要设法求出 leni 就可以了
而 leni 就是使得 i∈Sk 最大的 k ,容易求出
实现的时候,我们首先求出来 leni 和 i 在以它为最小值的区间中的位置,然后从小到大扫描一个 i ,每次将 i 放到一个长度为 leni 的没有用的区间中
考虑如何维护这个闲置的区间呢?
用一堆队列来维护所有长度为 i 的闲置区间的左端点,一开始的时候只有 1∈qn 每次确定一个数字之后就会将一个闲置的区间分成两部分
时间复杂度 O(n2)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| #include <iostream> #include <cstdio> #include <algorithm> #include <string> #include <cstring> #include <queue> using namespace std; const int maxn=805; int n,k; int a[maxn]; int seg[maxn][maxn]; queue <int> q[maxn]; int main() { cin>>n; for(int i=1;i<=n;i++) { for(int j=1;j<=n-i+1;j++) { int x; cin>>x; seg[i][x]++; } } q[n].push(1); for(int x=1;x<=n;x++) { int len=0; for(int i=n;i>=1;i--) { if(seg[i][x]>0) { len=i; break; } } int k=0; for(int j=1;j<=len;j++) { if(seg[j][x]==len-j+1) { k=j-1; break; } } int l=q[len].front(); q[len].pop(); a[l+k]=x; if(k>0) q[k].push(l); if(len-k-1>0) q[len-k-1].push(l+k+1); } for(int i=1;i<=n;i++) cout<<a[i]<<" "; cout<<'\n'; return 0; }
|