P17143 [NOI 2026] 中位数 题解
题目链接:P17143 [NOI 2026] 中位数,#18986. 中位数
简单题。二分答案,暴力 dp 的时间复杂度是 $ O(n^2klogn) $ 的,据说线段树优化可以做到 $ O(nklog^2n) $,但是我写假了。考虑找到任意 $ \lceil \frac{k}{2}\rceil $ 个中位数大于等于当前要求的中位数的段,显然这个最多会把整个序列分成 $ 2\lceil \frac{k}{2}\rceil + 1 $ 段,于是对于偶数 $ k $ 我们需要消掉一段,奇数 $ k $ 需要消掉两段。只要有一段中位数合法的段时序列的前缀或者后缀,或者两段合法的段是相邻的,就可以少掉一段,于是做简单分讨即可,然后发现这样对于 $ k=2, 3, 5 $ 时错了,那么拼上一个刚刚的线段树优化 dp 即可,但是我不会,所以我写了分讨。
代码:
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#include"median.h"
using namespace std;
void init(int c,int t)
{
return ;
}
vector<int> p,s;
int dp[1000005][6];
int tree[8000009];
void build(int l,int r,int id)
{
tree[id]=0;
if(l==r)
{
return ;
}
int mid=l+r>>1;
build(l,mid,id<<1);
build(mid+1,r,id<<1|1);
return ;
}
int query(int l,int r,int id,int qr)
{
if(r<=qr)return tree[id];
int mid=l+r>>1,ret=0;
ret|=query(l,mid,id<<1,qr);
if(mid<qr)ret|=query(mid+1,r,id<<1|1,qr);
// cout<<l<<' '<<r<<' '<<ret<<'\n';
return ret;
}
void update(int l,int r,int id,int x)
{
if(l==r)
{
tree[id]=1;
return ;
}
int mid=l+r>>1;
if(x<=mid)update(l,mid,id<<1,x);
else update(mid+1,r,id<<1|1,x);
tree[id]=(tree[id<<1]|tree[id<<1|1]);
return ;
}
void print(int l,int r,int id)
{
// cout<<l<<' '<<r<<' '<<tree[id]<<'\n';
if(l==r)
{
return ;
}
int mid=l+r>>1;
print(l,mid,id<<1);
print(mid+1,r,id<<1|1);
return ;
}
bool check(int x,int K)
{
int cnt=0,n=p.size();
// if(K==89)cout<<x<<'\n';
for(int i=0;i<n;i++)
{
cnt+=p[i];
// if(K==89)cout<<p[i]<<' ';
}
// if(K==89)puts("");
if(cnt<(K+1)/2)return 0;
if(K>5||K==4)
{
int cnt2=0,pos1=-1,pos2=-1;
cnt=0;
for(int i=0;i<n;i++)
{
cnt+=p[i];
if(cnt>=(i+2)/2)
{
pos1=i;
break;
}
}
cnt=0;
for(int i=n-1;i>=0;i--)
{
cnt+=p[i];
if(cnt>=(n-i+1)/2)
{
pos2=i;
break;
}
}
if(K%2==0)
{
if(pos1!=-1)
{
cnt=0;
for(int i=pos1+1;i<n;i++)
{
cnt+=p[i];
}
if(cnt>=(K-1)/2)return 1;
}
if(pos2!=-1)
{
cnt=0;
for(int i=0;i<pos2;i++)
{
cnt+=p[i];
}
if(cnt>=(K-1)/2)return 1;
}
for(int i=1;i<n;i++)
{
if(p[i]==1&&p[i-1]==1)return 1;
}
for(int i=2;i<n;i++)
{
if(p[i]==1&&p[i-2]==1)return 1;
}
for(int i=3;i<n;i++)
{
if(p[i]==1&&p[i-3]==1)return 1;
}
return 0;
}
else
{
// if(x==4229)
// {
// cout<<pos1<<' '<<pos2<<' '<<n<<'\n';
// for(int i=0;i<n;i++)
// {
// cout<<p[i]<<' ';
// }
// puts("");
// }
if(pos1!=-1)
{
cnt=0;
for(int i=pos1+1;i<n;i++)
{
cnt+=p[i];
}
if(cnt>=(K-1)/2)
{
for(int i=pos1+2;i<n;i++)
{
if(p[i]==1&&p[i-1]==1)return 1;
}
for(int i=pos1+3;i<n;i++)
{
if(p[i]==1&&p[i-2]==1)return 1;
}
for(int i=pos1+4;i<n;i++)
{
if(p[i]==1&&p[i-3]==1)return 1;
}
if((pos1+1<n&&p[pos1+1]==1)||(pos1+2<n&&p[pos1+2]==1)||(pos1%2==0&&p[pos1+3]==1))return 1;
}
}
if(pos2!=-1)
{
cnt=0;
for(int i=0;i<pos2;i++)
{
cnt+=p[i];
}
if(cnt>=(K-1)/2)
{
for(int i=1;i<pos2;i++)
{
if(p[i]==1&&p[i-1]==1)return 1;
}
for(int i=2;i<pos2;i++)
{
if(p[i]==1&&p[i-2]==1)return 1;
}
for(int i=3;i<pos2;i++)
{
if(p[i]==1&&p[i-3]==1)return 1;
}
if((pos2>0&&p[pos2-1]==1)||(pos2>1&&p[pos2-2]==1)||(pos2%2!=n%2&&pos2>2&&p[pos2]==1))return 1;
}
}
pos1=-1,pos2=-1;
cnt2=0;
for(int i=1;i<n;i++)
{
if(p[i]==1&&p[i-1]==1)cnt2++;
}
for(int i=2;i<n;i++)
{
if(p[i]==1&&p[i-2]==1)cnt2++;
}
for(int i=3;i<n;i++)
{
if(p[i]==1&&p[i-3]==1)
{
cnt2++;
if(pos1==-1)pos1=i;
else pos2=i;
}
}
if(cnt2>2||(cnt2==2&&(pos1==-1||pos2==-1||pos1+3!=pos2)))return 1;
return 0;
}
return 0;
}
else if(K==2)
{
cnt=0;
for(int i=0;i<n;i++)
{
cnt+=p[i];
if(cnt>=(i+2)/2)return 1;
}
cnt=0;
for(int i=n-1;i>=0;i--)
{
cnt+=p[i];
if(cnt>=(n-i+1)/2)return 1;
}
return 0;
}
else if(K==3)
{
int cnt2=0,pos1=-1,pos2=-1;
cnt=0;
for(int i=0;i<n;i++)
{
cnt+=p[i];
if(cnt>=(i+2)/2)
{
pos1=i;
break;
}
}
cnt=0;
for(int i=n-1;i>=0;i--)
{
cnt+=p[i];
if(cnt>=(n-i+1)/2)
{
pos2=i;
break;
}
}
// cout<<x<<' '<<pos1<<' '<<pos2<<'\n';
if(pos1!=-1&&pos2!=-1&&pos1+1<pos2)return 1;
if(pos1!=-1)
{
cnt=0;
for(int i=pos1+1;i<n;i++)
{
cnt+=p[i];
if(cnt>=(i-pos1+1)/2)return 1;
}
}
if(pos2!=-1)
{
cnt=0;
for(int i=pos2-1;i>=0;i--)
{
cnt+=p[i];
if(cnt>=(pos2-i+1)/2)return 1;
}
}
return 0;
}
else
{
int cnt2=0,pos1=-1,pos2=-1;
cnt=0;
for(int i=0;i<n;i++)
{
cnt+=p[i];
if(cnt>=(i+2)/2)
{
pos1=i;
break;
}
}
cnt=0;
for(int i=n-1;i>=0;i--)
{
cnt+=p[i];
if(cnt>=(n-i+1)/2)
{
pos2=i;
break;
}
}
// if(x==3384)
// {
// cout<<x<<' '<<pos1<<' '<<pos2<<' '<<n<<'\n';
// for(int i=0;i<n;i++)
// {
// cout<<p[i]<<' ';
// }
// puts("");
// for(int i=0;i<=n;i++)
// {
// for(int j=i+1;j<n;j++)
// {
// for(int k=)
// }
// }
// }
if(pos1!=-1)
{
int pos3=-1;
cnt=0;
for(int i=pos1+1;i<n;i++)
{
cnt+=p[i];
if(cnt>=(i-pos1+1)/2)
{
pos3=i;
break;
}
}
if(pos3!=-1)
{
for(int i=pos3+1;i<n;i++)
{
if(p[i]==1)return 1;
}
}
for(int i=pos1+2;i<n;i++)
{
if(p[i]==1&&p[i-1]==1)return 1;
}
for(int i=pos1+3;i<n;i++)
{
if(p[i]==1&&p[i-2]==1)return 1;
}
for(int i=pos1+4;i<n;i++)
{
if(p[i]==1&&p[i-3]==1)return 1;
}
if(pos2!=-1)
{
for(int i=pos1+1;i<pos2;i++)
{
if(p[i]==1)return 1;
}
}
}
for(int i=0;i<n/2;i++)
{
swap(p[i],p[n-1-i]);
}
pos1=-1,pos2=-1;
cnt=0;
for(int i=0;i<n;i++)
{
cnt+=p[i];
if(cnt>=(i+2)/2)
{
pos1=i;
break;
}
}
cnt=0;
for(int i=n-1;i>=0;i--)
{
cnt+=p[i];
if(cnt>=(n-i+1)/2)
{
pos2=i;
break;
}
}
if(pos1!=-1)
{
int pos3=-1;
cnt=0;
for(int i=pos1+1;i<n;i++)
{
cnt+=p[i];
if(cnt>=(i-pos1+1)/2)
{
pos3=i;
break;
}
}
if(pos3!=-1)
{
for(int i=pos3+1;i<n;i++)
{
if(p[i]==1)return 1;
}
}
for(int i=pos1+2;i<n;i++)
{
if(p[i]==1&&p[i-1]==1)return 1;
}
for(int i=pos1+3;i<n;i++)
{
if(p[i]==1&&p[i-2]==1)return 1;
}
for(int i=pos1+4;i<n;i++)
{
if(p[i]==1&&p[i-3]==1)return 1;
}
if(pos2!=-1)
{
for(int i=pos1+1;i<pos2;i++)
{
if(p[i]==1)return 1;
}
}
}
// for(int i=0;i<n;i++)
// {
// cout<<p[i]<<' ';
// }
// puts("");
for(int i=2;i<n;i++)
{
if(p[i]==1&&p[i-1]==1&&p[i-2]==1)return 1;
}
for(int i=3;i<n;i++)
{
if(p[i]==1&&p[i-1]==1&&p[i-2]==0&&p[i-3]==1)return 1;
}
for(int i=3;i<n;i++)
{
if(p[i]==1&&p[i-1]==0&&p[i-2]==1&&p[i-3]==1)return 1;
}
for(int i=4;i<n;i++)
{
if(p[i]==1&&p[i-1]==0&&p[i-2]==1&&p[i-3]==0&&p[i-4]==1)return 1;
}
for(int i=4;i<n;i++)
{
if(p[i]==1&&p[i-1]==1&&p[i-2]==0&&p[i-3]==0&&p[i-4]==1)return 1;
}
for(int i=4;i<n;i++)
{
if(p[i]==1&&p[i-1]==0&&p[i-2]==0&&p[i-3]==1&&p[i-4]==1)return 1;
}
for(int i=5;i<n;i++)
{
if(p[i]==1&&p[i-1]==0&&p[i-2]==1&&p[i-3]==0&&p[i-4]==0&&p[i-5]==1)return 1;
}
for(int i=5;i<n;i++)
{
if(p[i]==1&&p[i-1]==0&&p[i-2]==0&&p[i-3]==1&&p[i-4]==0&&p[i-5]==1)return 1;
}
for(int i=6;i<n;i++)
{
if(p[i]==1&&p[i-1]==1&&p[i-2]==0&&p[i-3]==0&&p[i-4]==0&&p[i-5]==1&&p[i-6]==1)return 1;
}
for(int i=7;i<n;i++)
{
if(p[i]==1&&p[i-1]==0&&p[i-2]==0&&p[i-3]==1&&p[i-4]==0&&p[i-5]==0&&p[i-6]==1&&p[i-7]==1)return 1;
}
for(int i=7;i<n;i++)
{
if(p[i]==1&&p[i-1]==1&&p[i-2]==0&&p[i-3]==0&&p[i-4]==1&&p[i-5]==0&&p[i-6]==0&&p[i-7]==1)return 1;
}
for(int i=7;i<n;i++)
{
if(p[i]==1&&p[i-1]==0&&p[i-2]==1&&p[i-3]==0&&p[i-4]==0&&p[i-5]==0&&p[i-6]==1&&p[i-7]==1)return 1;
}
for(int i=7;i<n;i++)
{
if(p[i]==1&&p[i-1]==1&&p[i-2]==0&&p[i-3]==0&&p[i-4]==0&&p[i-5]==1&&p[i-6]==0&&p[i-7]==1)return 1;
}
return 0;
}
}
int median(int n,int K,vector<int> a)
{
p.assign(n,0);
s.assign(n,0);
int l=1,r=n,ans=0;
while(l<=r)
{
int mid=l+r>>1;
for(int i=0;i<n;i++)
{
p[i]=(a[i]>=mid);
}
if(check(mid,K))l=mid+1,ans=mid;
else r=mid-1;
}
// for(int i=0;i<n;i++)
// {
// p[i]=(a[i]>=78);
// }
// check(78,K);
// for(int i=0;i<n;i++)
// {
// p[i]=(a[i]>=79);
// }
// check(79,K);
return ans;
}
//#include <bits/stdc++.h>
//#include "median.h"
//
//signed main() {
// freopen("median4.in","r",stdin);
// int c, t;
// std::cin >> c >> t;
// init(c, t);
// for (int _ = 0; _ < t; _++) {
// int n, k;
// std::cin >> n >> k;
// if(_==16)cout<<k<<'\n';
// std::vector<int> a(n);
// for (int i = 0; i < n; i++) std::cin >> a[i];
// std::cout << median(n, k, a) << '\n';
// }
// return 0;
//}

浙公网安备 33010602011771号