传送门:
题意:对于一个序列,要求把它切分成若干段,使得每一段中值域∈[x,y]的数的个数 大于 其他数的个数。求最多能切分成多少段。
分析:设cnt1为∈[x,y]中的数的个数,设f[l,r]=cnt1-(n-cnt1)=2*cnt1-n,显然当f[l,r]>1时均可再分,故最终所有段的f[l,r]都为1,最终切成的段数即为2*cnt1-n。
此时,若规定段数k,要求最小值域区间,双指针即可。
代码:
#include<bits/stdc++.h>
using namespace std;
int a[100005];
int main()
{
int t;
cin>>t;
while(t--)
{
int n,m;
cin>>n>>m;
int cnt=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
if(a[i]<m) cnt++;
}
if(n-2*cnt<=0) puts("-1");
else cout<<n-2*cnt<<endl;
}
}
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,k;
int a[200005];
int cnt[200005];
int pre[200005];
int ansl[200005],ansr[200005];
int check(int l,int r)
{
int cnt=pre[r]-pre[l-1];
if(2*cnt-n>=k) return 1;//至少能分成k组
return 0;
}
signed main()
{
int t;
cin>>t;
while(t--)
{
int maxx=0;
cin>>n>>k;
for(int i=1;i<=n;i++)
{
cnt[i]=pre[i]=0;
}
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
maxx=max(maxx,a[i]);
cnt[a[i]]++;
}
for(int i=1;i<=maxx;i++)
{
pre[i]=pre[i-1]+cnt[i];
}
int minn=0x3f3f3f3f;
int pos=1;
int x=1,y=maxx;
for(int i=1;i<=maxx;i++)//双指针找最小值域区间
{
while(!check(i,pos)&&pos<=maxx) pos++;
if(pos==maxx+1) break;
int len=pos-i+1;
if(len<minn)
{
minn=len;
x=i;
y=pos;
}
}
cout<<x<<" "<<y<<endl;
int cnt=0;
int num=0;
ansl[++num]=1;
for(int i=1;i<=n;i++)
{
if(k==1)//至少能分成k组 对于最后一段一起取完
{
ansr[num]=n;
break;
}
if(a[i]>=x&&a[i]<=y) cnt++;
else cnt--;
if(cnt>0)
{
cnt=0;
ansr[num]=i;
ansl[++num]=i+1;
k--;
}
}
for(int i=1;i<=num;i++)
{
cout<<ansl[i]<<" "<<ansr[i]<<endl;
}
}
}