AT_agc058_e [AGC058E] Nearer Permutation 题解
nkrqzjc_zzz · · 题解
题目链接
题目思路
为方便起见,指数和数值均以
首先,让我们考虑如何找到
让
- 设
result=(),s=Invs/2 。 - 执行下面的操作
N 次。 - 设
x_m 是x_0,x_1,\cdots,x_{\min(\lfloor s\rfloor,N-1)} 中的最小值。 - 将
x_m 附加到result 的末尾。 - 从
x 中删除x_m 。 - 设
s=s-m 。 - 返回
result 。
取最小的索引 Yes。
从上面操作的执行方式可以看出,执行操作
-
- 如果
A_{k+1} 从x 中删除,A_k,A_{k+2},A_{k+3},\cdots,A_{N-1} 将按此顺序排列。
因此,可以看出,满足
- 设
B=A 。 - 对于
i=k+1,k-1,k-2,\cdots,0 ,执行以下操作。 - 将
B_i 向右移动。更准确地说,将B_i,B_{i+1},\cdots,B_{i+t} 更改为B_{i+1},\cdots,B_{i+t},B_i ,其中t 是移动的长度。这里,B_i<B_{i+j} (1\leq j\leq t )必须保持(在操作之前)。此外,如果i=k+1 ,则A_k<B_{i+j} 必须存在。
对于每个
在执行操作
首先,考虑
在
毕竟,无论哪种情况,
现在,让我们尝试这两个值。(事实上,仅考虑
由于
如果在根据上述策略决定 No;否则为 Yes。
该方法的时间复杂度为
代码
码风稍稍有点差,见谅!
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
#define int ll
template<class t,class u> bool m(t&a,u b){if(b<a){a=b;return 1;}else return 0;}
template<class t> using v=vector<t>;
using o=v<int>;
o rv(int n,int f=0){
int j;o v(n);
for(int i=0;i<n;i++)scanf("%lld",&j),v[i]=j+f;
return v;
}
template<class t>
struct g{
int s;v<t> e;
g(int n=0){it(n);}g(const v<t>&a){it(a);}
void it(int n){e.clear();e.resize(s=n);}
void it(const v<t>&a){
s=si(a);
e.resize(s);
for(int i=0;i<s;i++)e[i]=a[i];
for(int i=0;i<s;i++){
int j=i+(i+1)&(-i-1);
if(j<s)e[j]+=e[i];
}
}
void ad(int i,t v){
for(;i<s;i+=(i+1)&(-i-1))e[i]+=v;
}
t ge(int i){
t r=t();
for(;i>=0;i-=(i+1)&(-i-1))r+=e[i];
return r;
}
t d(int b,int e){
return ge(e-1)-ge(b-1);
}
};
int xu(o q){
int n=int(q.size()),d=0;
g<int> y(n);
for(int i=0;i<n;i++)d+=i-y.ge(q[i]),y.ad(q[i],1);
return d;
}
bool er(const o&p){
int n=int(p.size()),k=-1,h;
for(int i=n-1;i>=0;i--)if(p[i]>p[i+1])k=i;
if(k==-1)return 1;
o q(n);for(int i=0;i<n;i++)q[p[i]]=i;
h=xu(p);
auto w=[&](int d){
int s=(h+d)>>1,r=n;
for(int v=0;v<p[k];v++){
if(v==p[k+1]){
for(int i=k+2;i<n;i++)if(p[i]<p[k])m(r,i);
int u=min(r-q[v]-1,d);
d-=u;m(r,k+1+u);
}else if(q[v]<k){
if(r<n&&r-q[v]<=s)return false;
int u=min(r-q[v]-1,d);
d-=u;s-=u;
}else m(r,q[v]);
}
return d==0;
};
for(int i=h-1;i<h+1;i++)if(w(i))return true;
return false;
}
int s,t;
main(){
scanf("%lld",&t);
while(t--){
scanf("%lld",&s);
o p=rv(s,-1);
if(er(p))puts("Yes");else puts("No");
}
}
管理员朋友辛苦了!