C. Nastya and Strange Generator
题目梗概:
给n个空格(可设为g[]),按要求往里以此填序列1到n.
从1到n填进g[]里
对于当前要填的数字k
构造两个数组:
for(1~n)
r[i]为g[]内还未被填数【i,n】区间的最小位置下标
ct[i]为r[]中每个数的出现次数
k必须放在ct[]中出现次数最多的地方之一
个人题解:
根据数据范围,直接模拟是O(n^2),肯定不行。
所以我决定找这个构造方法的潜在意义。
我们发现,当想让当前的k放进他给的序列里的相对位置,必须满足一些条件,那我们对于每个k,都判断一下能不能放进指定位置,判定n次,时间O(N).
首先,1 是可以随便放的。
而我们发现,除非你上一个就是放在队尾(或者说上一个放完后,g[]只填满了 任意~n 整个后缀,其他地方没放),这个时候,当前这个,可以随意放。否则,当前这个必须放在上一个元素的后面。
根据这个思路,就能实现代码了。
原理是 但你在g[]某个连续空缺的地方放一个k,假设放在 i , 那么会导致r[i]不能等于 i自己,必须等于i+1,这会导致i+1在ct[]里出现次数变多,间接导致i+1放下一个数的概率增大。
#include<bits/stdc++.h>
#define LL long long
#define INF 0x3f3f3f3f
#define mst(a,b) memset(a,b,sizeof(a))
using namespace std;
const int maxn=1e5+10;
struct node
{
int x,loc;
bool operator <(const node a)const
{
return x<a.x;
}
} f[maxn];
int g[maxn];
int main()
{
int t;
cin>>t;
while(t--)
{
mst(g,0);
int n;
cin>>n;
for(int i=1; i<=n; i++)
{
cin>>f[i].x;
f[i].loc=i;
}
if(n<=2)
puts("Yes");
else
{
sort(f+1,f+n+1);
int ed=n;
g[f[1].loc]=1;
int fl=0;
for(int i=2; i<n; i++)
{
if(f[i-1].loc==ed)
{
while(g[ed])ed--;
g[f[i].loc]=i;
}
else if(g[f[i].loc-1]==f[i-1].x)
{
g[f[i].loc]=i;
}
else
{
fl=1;
break;
}
}
if(fl)
puts("No");
else
puts("Yes");
}
}
}