LINK
题目描述
众所周知,温澈滢在宿舍养了一排 n 只狗狗,每只狗狗都有一个颜色 cic_ici 。同时,它们只喜欢和不同颜色的狗狗玩,否则它们会觉得很单调无趣。
也就是说,如果第 i 只狗狗和第 j 只狗狗颜色不同,那么它们可以拥有亲密关系,它们亲密度可以表示成 ∣ i − j ∣ ∣ i − j ∣ ∣ i − j ∣ ∣i−j∣\mid i-j\mid∣i−j∣ ∣i−j∣∣i−j∣∣i−j∣,否则它们就不能建立亲密关系。
当 n 只狗狗颜色两两不同时,它们有 n ( n − 1 ) 2 n ( n − 1 ) 2 2 n ( n − 1 ) n(n−1)2\frac{n(n-1)}{2}2n(n−1) n(n−1)22n(n−1)2n(n−1)对亲密关系;当 n 只狗狗的颜色完全一致时,它们之间就不存在任何一对亲密关系。
我们把这么多对亲密关系取出来,以亲密度为第一关键词,编号较小的狗狗的编号为第二关键词,编号较大的狗狗的编号为第三关键词排序(三维都按照升序排序)。
现在温澈滢想知道第 k 对亲密关系是哪一对狗狗,当然,必要的时候你可以告诉温澈滢这些狗狗之间不存在这么多的亲密关系。
输入描述:
第一行输入两个数字 n 和 k 。
第二行给出 n 个数字,第 i 个数字 c i ci ci 表示第 i 只狗狗的颜色。
输出描述:
如果存在第 k 对狗狗,请在一行内输出两只狗狗的编号,小的在前,中间用一个空格隔开。
否则输出 -1 。
思路
来自题解:
倘若我们知道了第k对亲密关系的亲密值是多少就好办了,显然可以二分, 那二分什么呢, 二分亲密度, 因为最终的排名就是按照亲密度升序排列, 我们只需找到当前的小于当前二分的亲密度的关系对数, 是不是大于k即可, 在查询小于k的亲密度关系对数是,可以用双指针, 维护一个差值为k的区间, 然后依次求出当前区间最左边中的元素与区间中所有元素的亲密度即可
这里借鉴别人的代码
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll N = 2e5 + 10;
ll c[N], vis[N], n, k;
ll check(ll mid)
{
for(ll i = 1; i <= n; i++) vis[i] = 0;
for(ll i = 1; i <= mid + 1; i++) vis[c[i]] ++;
ll ans = mid + 1 - vis[c[1]], len = mid + 1;
for(ll l = 2, r = mid + 2; l < n; r ++, l ++)
{
vis[c[l - 1]] --;
if(r <= n) vis[c[r]] ++;
else len --;
ans += len - vis[c[l]];
}
return ans;
}
int main()
{
cin >> n >> k;
for(ll i = 1; i <= n; i++) cin >> c[i];
ll l = 1, r = n - 1, ans = 0;
while(r >= l)
{
ll mid = l + r >> 1;
if(check(mid) >= k)r = mid - 1, ans = mid;
else l = mid + 1;
}
if(ans == 0)
{
cout << -1 << endl;
return 0;
}
ll las = check(ans - 1);
for(ll i = ans + 1; i <= n; i++)
{
if(c[i] == c[i - ans]) continue;
if(++las == k)
{
cout << i - ans << " " << i << endl;
return 0;
}
}
return 0;
}