小A的排列 题解
小A的排列
https://ac.nowcoder.com/acm/problem/22729
一个暴力是枚举左右端点,用 set
求中位数,然而是 的。
但是我们注意到,在加入一个数后,中位数至多只会移动 个位置,即不变或者变成前驱或后继。
于是我们需要支持一个 插入、 求前驱后继的数据结构,发现并找不到。
但是我们可以倒过来变成删除,这样子就可以用链表维护了。
// ==================================== // author: M_sea // website: https://m-sea-blog.com/ // ==================================== #include <bits/stdc++.h> #define file(x) freopen(#x".in","r",stdin); freopen(#x".out","w",stdout) #define debug(...) fprintf(stderr,__VA_ARGS__) using namespace std; typedef long long ll; int read() { int X=0,w=1; char c=getchar(); while (c<'0'||c>'9') { if (c=='-') w=-1; c=getchar(); } while (c>='0'&&c<='9') X=X*10+c-'0',c=getchar(); return X*w; } const int N=10000+10; const int mod=1e9+7; int n,p[N],seed,pw1[N],pw2[N]; struct H { int L[N],R[N]; int pre(int x) { return L[x]; } int nxt(int x) { return R[x]; } void del(int x) { R[L[x]]=R[x],L[R[x]]=L[x]; } } A,B; int main() { n=read(),seed=read(); for (int i=1;i<=n;++i) p[i]=read(); pw1[0]=1; for (int i=1;i<=n;++i) pw1[i]=1ll*pw1[i-1]*seed%mod; pw2[0]=1; for (int i=1;i<=n;++i) pw2[i]=1ll*pw2[i-1]*pw1[n]%mod; for (int i=1;i<=n+1;++i) B.L[i]=i-1,B.R[i-1]=i; int ans=0; for (int r=n,M1=(n+1)>>1,M2=(n+2)>>1;r;--r) { int m1=M1,m2=M2; A=B; for (int l=1;l<=r;++l) { ans=(ans+1ll*pw2[l-1]*pw1[r]%mod*(m1+m2))%mod; if (m1==m2) { if (p[l]<=m2) m2=A.nxt(m2); if (p[l]>=m1) m1=A.pre(m1); } else { if (p[l]<=m1) m1=A.nxt(m1); if (p[l]>=m2) m2=A.pre(m2); } A.del(p[l]); } if (M1==M2) { if (p[r]<=M2) M2=B.nxt(M2); if (p[r]>=M1) M1=B.pre(M1); } else { if (p[r]<=M1) M1=B.nxt(M1); if (p[r]>=M2) M2=B.pre(M2); } B.del(p[r]); } printf("%d\n",ans); return 0; }