梦熊联盟 #7 Solution
前言
听闻梦熊联盟开了个新网站,遂来捧个人场。
感觉他们对入门难度有一些误解。
题目在这。
思路
可以将倍增的过程看作数组中两个相邻的数向某个数逼近的过程。
解题方法
由于 \(k\) 很小,考虑暴力逼近。
对于输入的 \(x\),若 \(a_1>x\) 或 \(a_n<x\) 那么显然不会存在。
否则,找到第一个不小于 \(x\) 的数 \(a_y\),若 \(a_y=x\) 则显然存在。
否则,进行 \(k\) 次暴力逼近,若在某次逼近中左右区间的平均数为 \(x\),那么存在。
否则不存在。
复杂度
时间复杂度
每次查询时 \(O(\log n)\) 查找第一个不小于 \(x\) 的数,并进行 \(k\) 次暴力逼近,\(q\) 次询问,则时间复杂度为 \(O(n+q(k+\log n))=O(qk)\)。
空间复杂度
仅需存储数组本身, 空间复杂度为 \(O(n)\)。
Code
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e3 + 10;
using ll = long long;
int n, q, k;
ll a[N], x, l, r, *ptr, mid;
void run()
{
scanf("%d%lld", &k, &x);
if (x > a[n] or x < a[1])
{
puts("No");
return;
}
ptr = lower_bound(a + 1, a + n + 1, x);
if (*ptr == x)
{
puts("Yes");
return;
}
r = *ptr, l = *(ptr - 1);
for (int i = 1; i <= k; i++)
{
mid = (l + r) >> 1ll;
if (mid == x)
return puts("Yes"), void();
if (mid > x)
r = mid;
else
l = mid;
}
puts("No");
}
int main()
{
scanf("%d%d", &n, &q);
for (int i = 1; i <= n; i++)
{
scanf("%lld", a + i);
}
for (int i = 1; i <= q; i++)
{
run();
}
}