[2021.7.16] 洛谷七月月赛
作者:互联网
题目
天体探测仪(Astral Detector)
解法
当时想了很久如何通过每层区间依次查找数值下标,然而半天只会推 \(1\)...
实在不知道是怎么想到的,我们令 \(i\) 为最小值的最大区间为 \([l_i,r_i]\),令 \(len_i=r_i-l_i+1\)。
事实上,\(len_i\) 就是最大的能满足 \(i\in S_j\) 的 \(j\)。
那么 \(i\) 在排列中的位置一定在 \([l_i,r_i]\) 内,令其为 \(l_i+pos\)(不妨设 \(i\) 与 \(l_i\) 的距离大于与 \(r_i\) 的距离)。考虑 \(j\le len_i\),在所有属于 \([l_i,r_i]\) 的长度为 \(j\) 的区间中若都包含 \(i\),那么 \(S_j\) 中应有且只有 \(len_i-j+1\) 个 \(i\)。容易发现 \(pos\) 应该是最大的满足属于 \([l_i,r_i]\) 的长度为 \(j\) 的区间中不都包含 \(i\) 的 \(j\)。
至此,我们若求得 \(l_i,r_i\) 中一个就能确定 \(i\) 的位置了。
再做一个观察,我们发现 \(1\) 可以将 \([1,n]\) 分成两个隔断的小区间,因为 数据保证有解,所以一定有数是这两个小区间的最大值!而且,如果我们从小到大枚举数值,容易得出某数 \(i\) 的 \([l_i,r_i]\) 一定不会包含几个被隔断的区间。
还有一点要说的是,\(l_i+pos\) 和 \(r_i-pos\) 其实都是合法解,不过这两种情况隔断的区间长度相同,而且隔断区间实际上是孤立的,所以随便选一个就好了。
基于此,我们可以开一个 vector
\(f_i\) 维护某个长度为 \(i\) 的隔断区间可能的左端点(也即维护 \(l_i\)),这样就在 \(\mathcal O(n^2)\) 内解决了此题。
代码
#include <queue>
#include <cstdio>
using namespace std;
#define print(x,y) write(x),putchar(y)
template <class T> inline T read(const T sample) {
T x=0; int f=1; char s;
while((s=getchar())>'9'||s<'0') if(s=='-') f=-1;
while(s>='0'&&s<='9') x=(x<<1)+(x<<3)+(s^48),s=getchar();
return x*f;
}
template <class T> inline void write(const T x) {
if(x<0) return (void) (putchar('-'),write(-x));
if(x>9) write(x/10);
putchar(x%10^48);
}
const int maxn=805;
int n,cnt[maxn][maxn],tp[maxn];
int ans[maxn];
queue <int> q[maxn];
int main() {
n=read(9);
for(int i=1;i<=n;++i)
for(int j=1;j<=n-i+1;++j) {
int x=read(9);
++cnt[i][x],tp[x]=i;
}
q[n].push(1);
for(int i=1;i<=n;++i) {
int pos=0;
for(int j=tp[i]-1;j;--j)
if(cnt[j][i]<tp[i]-j+1) {
pos=j; break;
}
int len=tp[i];
int p=q[len].front();
q[len].pop();
ans[p+pos]=i;
q[pos].push(p);
q[len-pos-1].push(p+pos+1);
}
for(int i=1;i<=n;++i)
print(ans[i],' ');
puts("");
return 0;
}
标签:月赛,洛谷,2021.7,int,pos,len,隔断,maxn,区间 来源: https://www.cnblogs.com/AWhiteWall/p/15018499.html