您的位置:首页 > 健康 > 养生 > CF 963 D. Med-imize

CF 963 D. Med-imize

2024/12/23 0:22:17 来源:https://blog.csdn.net/qq_74190237/article/details/141035363  浏览:    关键词:CF 963 D. Med-imize

原题链接:Problem - D - Codeforces

题意:给一个长度为n的数组,每次从数组中删去一段长度为k的连续子数组,如果数组长度小于等于k就停止删除,问最终数组的中位数最大是多少?

思路:二分+dp。从题目中可以的到的信息是,最终的数组长度一定小于等于k。那么很容易可以想到二种特殊情况,第一种是k=1的时候,中位数是数组里面最大的数,第二种是如果一次也不要删,那么可以直接取出中位数。

对于剩下的普遍情况,可以能够明显想到的是在数组里面肯定有些数是不可能加入最终数组的。那么什么数有可能成为最终的数组?

如果n可以被k整除那么,最终的数组长度就是k,如果不能整除,那么最终的数组长度就是n%k。那么这最终数组里面可以是什么数呢?首先数组下标从0开始,举个例子,如果n=8,k=3,那么数组的下标是:0,1,2,3,4,5,6,7,将这些下标全部对k取余,下标就是:0,1,2,0,1,2,0,1。可以发现随便删除3个连续的数字,留下来的一定是0,1,2这个循环节,并且8%3=2,所以留下来的下标一定是0,1。可以发现这个规律普遍存在全部的情况,那么可以抽象一下,最终数组的长度是v,那么能够构成这个数组的元素在原数组中,下标对k取余之后的值是,0,1,2,3,......,v-1。

对于最终的数组,一定要排序才可以知道中位数是多少吗?其实不用的。如果中位数是x,使用一个数来记录一下,那么大于等于x那么就+1,否则-1,如果最终的数大于0就代表x可以是中位数。注意这只是说大于等于x可以是中位数,但不是指x是中位数,例如:1 2 2 6 6 6 6 6 8 9 9,大于等于2的数有很多。看例子可以发现满足二分性质,所以可以二分中位数来求解这个问题。

总结一下,如果k=4,n=7,数组下标就是:0,1,2,3,0,1,2。最终数组的长度就是3,最终待选的下标是:0,1,2,0,1,2 。例如删前面的4个数就是后面的0,1,2,删中间的就是前面的0,后面的1,2。如果将这些数堆起来看呢?

0,1,2

0,1,2

那么就可以抽象成从0走到2,最终大于中位数的数是不是大于0就可以了,这样堆起来看就明显可以发现dp的转移方程了,具体见代码。

//冷静,冷静,冷静
//调不出来就重构
#pragma GCC optimize(2)
#pragma GCC optimize("O3")
#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<ll,ll> pii;
const int N=1e6+10,mod=1000000007;
vector<vector<ll>> mp;
ll chang,kuan,p[N];
bool is(ll x)
{vector<vector<ll>> f(chang+10,vector<ll>(kuan+10,-1e9));for(int i=1;i<=chang;i++){for(int j=1;j<=kuan;j++){if(j==1){if(mp[i][j]>=x)f[i][j]=1;else f[i][j]=-1;if(i>1){f[i][j]=max(f[i-1][j],f[i][j]);}continue;}if(i==1){f[i][j]=max(f[i][j],f[i][j-1]+(mp[i][j]>=x?1:-1));continue;}f[i][j]=max(f[i][j],f[i-1][j]);f[i][j]=max(f[i][j],f[i][j-1]+(mp[i][j]>=x?1:-1));f[i][j]=max(f[i][j],f[i-1][j-1]+(mp[i][j]>=x?1:-1));}}for(int i=1;i<=chang;i++){if(f[i][kuan]>0)return 1;}return 0;
}
void jiuyuan()
{ll n,m;cin>>n>>m;//如果写上二种情况的特判,可以快700msfor(int i=1;i<=n;i++){cin>>p[i];}chang=n/m+(n%m>0);kuan=(n%m==0?m:n%m);
//	cout<<n/m<<' '<<(n%m>0)<<endl;vector<vector<ll>> op(chang+10,vector<ll>(kuan+10));mp=op; 
//	cout<<chang<<' '<<kuan<<endl;for(int i=1;i<=chang;i++){for(int j=1;j<=kuan;j++){mp[i][j]=p[(i-1)*m+j];}}ll l=1,r=1e9;while(l+1<r){ll mid=l+r>>1;if(is(mid))l=mid;else r=mid;}if(is(r))l=r;cout<<l<<endl;
}
int main()
{ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);ll T=1;cin>>T;while(T--){jiuyuan();}return 0;
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com