前言
我的做法也是成功的拿到了最优解,开一瓶可乐(其实只喝得起免费的学校饮用水)庆祝。顺便说一句,INTP男叫柯乐。但这显然并不是重点。
只是一个简单的小优化,大家可以看到,只有2行(显然不是章鱼的核聚变,不过用了以后可以直达RE-0ms,很强的)。
咳咳,扯远了。
言归正传:
题目内容
你有一个序列\(a_1, a_2, \dots, a_n\) 。 定义\(b_{l, r}\) 表示序列 \(\{a_i\} _ {l\leq i \leq r}\) 的中位数。
定义 \(c_{i,j}\) 为序列\(\{b_{i, j}\} _ {l\leq i \leq j \leq r}\) 的中位数。 求\(\{c_{i, j}\} _ {1\leq i \leq j \leq n}\) 的中位数是多少。
对于一个大小为\(m\) 的序列,我们定义它的中位数为第 \(\lceil(\frac{m}{2})\rceil\)小的数字。
\(n\leq 2000,a_i\leq10^9\)
思路
我们考虑求“中位数的中位数”,使用二分答案搭配树状数组求解。那这道题我们也可以使用二分答案。
类似的,当我们二分“中位数为\(x\)”时,我们把\(a\)中\(< x\)的权值设为\(-1\),否则设为\(1\)
然后我们便可以求出\(f\),\(i\sim j\)中\(\ge x\)的数较多,\(f_{i,j}=1\),否则为\(-1\)。
随后我们便可以使用容斥,得到\(dp_{i,j}=f_{i,j}-dp_{i+1,j-1}+dp_{i+1,j}+dp_{i,j-1}\)
随后看看\(dp_{i,j}\)是否大于\(0\),累加\(1\ or\ -1\)后与\(\frac{n\times(n+1)}{4}\)比较大小。
然后就没有然后了。
代码
#include<bits/stdc++.h>
using namespace std;
#define N 2004
int t[N],n,m,i,j,a[N],s[N],p,f[N][N],dp[N][N],l,r,mid,ans,b[N];
int ch(int x){int p=0,k,t;for(int i=1;i<=n;i++){if(a[i]>=x) s[i]=s[i-1]+1;else s[i]=s[i-1]-1;}for(int i=1;i<=n;i++){for(int j=i;j<=n;j++){if(s[j]-s[i-1]>0){f[i][j]=1;}else f[i][j]=-1;}}for(int i=n;i>=1;i--){for(j=i;j<=n;j++){dp[i][j]=f[i][j]+dp[i+1][j]+dp[i][j-1]-dp[i+1][j-1];if(dp[i][j]>0){p++;}else p--;}}return p>0;
}
int main()
{cin>>n;for(i=1;i<=n;i++){scanf("%d",&a[i]);r=max(a[i],r);}l=1;while(l<=r){mid=(l+r)/2;if(ch(mid)){ans=mid;l=mid+1;}else{r=mid-1;}}cout<<ans;
}