D 温澈滢的狗狗
思路
这个题目看了我好久,,(主要是太菜了)
做题的时候想到了用二分,但是不知道怎么去定义它的性质。
两两不同颜色的狗之间会产生亲密度,对每一对有亲密度的狗按照关键词进行排序,求第k对狗的下标。
如果模拟的话肯定会超时,所以要往快速找到第k对狗的方向想,会想到使用二分思想。
想到用二分思想就要想能不能找到一个能够二分的条件。
第一关键词是按照亲密度去的,所以想想能不能以亲密度去划分。
我们假设第k对的亲密度为x,那么就说明 的部分是不需要的,所以就有明显的二分性。
知道了以亲密度作为判断条件,那么接下来的步骤就是完善细节,计算每个亲密度的个数。
只有颜色不同才会有亲密度,直接求有点麻烦,时间复杂度也会比较高,直接求不行,那么就试试间接的求法:
设x为亲密度,我们将同色点都放到同一个下标的数组中。
总点对数 :
我们知道亲密度了,(亲密度是下标距离)那么从下标1开始到(n - x) 分别做区间,每个区间都可以取x个数与区间第一个点形成对,有(n - x )个区间,所以就为, 后部分区间不能延长了,到达总下标的末端了,所以可取值分别为
,等差数列求和就得出了
。
同色点数利用双指针求解即可(这个不知道怎么用讲,看代码吧。)
二分具体条件出来了,那么就可以求出来最大亲密度为 总对数小于
的
值。
所以第k对狗的亲密度为。
亲密度知道了,直接for循环找即可。
AC代码
#include<bits/stdc++.h>
using namespace std;
#define _for(i, a, b) for (int i = (a); i < (b); ++i)
#define _rep(i, a, b) for (int i = (a); i <= (b); ++i)
#define For(i, a, b) for (int i = (a); i >= (b); --i)
#define mod(x) (x) % MOD
#define debug(a) cout << #a << " = " << a << endl;
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
const int N = 100000 + 10;
int c[N], n;
ll k;
vi same[N];
ll cal(ll x)
{
ll tot = (n - x) * x + x * (x - 1) / 2;
_rep(i, 1, n)
{
int r = 0, sz = same[i].size();
_for (j, 0, sz)
{
while (r < sz && same[i][r] - same[i][j] <= x) ++r;
tot -= r - j - 1;
}
}
return tot;
}
int main()
{
#ifdef LOCAL
freopen("data.in", "r", stdin);
#endif
ios::sync_with_stdio(false);
cout.tie(0);
cin.tie(0);
cin >> n >> k;
_rep(i, 1, n)
{
cin >> c[i];
same[c[i]].push_back(i);
}
if (cal(n) < k) return puts("-1"), 0;
int l = 0, r = n;
while (l < r)
{
int mid = l + r + 1 >> 1;
if (cal(mid) < k) l = mid;
else r = mid - 1;
}
int dist = l + 1;
ll cnt = cal(l);
_rep(i, 1, n - dist) if (c[i] != c[i + dist])
{
cnt++;
if (cnt == k)
{
cout << i << " " << i + dist << endl;
break;
}
}
return 0;
} 
京公网安备 11010502036488号