题面描述
给定n个数 a1,…,an,高老师想了解al,…,ar中有多少对相邻元素值相同。高老师把这个数目定义为区间[l,r]的价值,用v[l,r]表示。例如 1,1,1,2,2 这五个数所组成的区间的价值为3。
现在高老师想知道在所有的v[l,r] (1≤l≤r≤n)中,第k小的值是多少。但高老师要和女朋友出去玩,于是他把这个问题甩给了你,请你帮他解决一下。
输入数据
第一行有一个整数t(1≤t≤30),表示有t组数据。
对于每组数据:
第一行有两个整数n,k (1≤n≤2000,1≤k≤n(n+1)/2);
第二行有n个整数a1,…,an (1≤ai≤109)。
输出数据
对于每组数据:
输出一个整数,表示第 k小的值。
样例输入
2
4 7
1 1 2 3
3 5
100 100 100
样例输出
0
1
这道题目与以前的区间价值老题目类似,但是这里的区间价值为区间内序列中相邻元素相等的个数,对于一个长度为n的序列,一共有n*(n+1)/2个区间,区间价值可能是0到n-1,求第k小的数,也就是将区间价值从小到大排列取第k个,我们这里区间价值可能的结果0—n-1用二分法,如果二分发左半部分的价值对应的区间数总和大于等于k,就说明第k个元素的价值在左半部分,反之则在右半部分,计算区间数总和的时候用尺取法,最终将时间复杂度降到O(nlogn),终于AC了。
有哪里不对的欢迎指出,第一次发,多多包涵,以后还会更一些平时写的有意思的小代码。
#include <iostream>
#include <algorithm>
using namespace std;
int getValue(int,int,int []);
int getsum(int m,int num[],int len)
{
int sum=0;
int en=0;
int thisValue=0;
for(int i=0; i<len; i++)
{
while(en<len)
{
if(thisValue<=m)
{
en++;
thisValue+=num[en-1];
}
else
break;
}
sum+=en-i;
thisValue-=num[i];
}
return sum;
}
int main()
{
int T;
cin>>T;
for(int i=0; i<T; i++)
{
int n,k;
cin>>n>>k;
int a[n];
int Nnum[n];
for(int j=0; j<n; j++)
{
cin>>a[j];
if(j>0&&a[j]==a[j-1])
{
Nnum[j-1]=1;
}
else
{
if(j>0)
Nnum[j-1]=0;
}
}
int left=0;
int right=n-1;
while(left<right)
{
int m=(left+right)/2;
if(getsum(m,Nnum,n)>=k)
right=m;
else
left=m+1;
}
cout<<left<<endl; }
return 0;
}