题目:
思路:
我们不难发现本题和 mod 有关,想这种难以维护所有情况的时候,我们可以往根号算法上想
本题中值域为 V = 3e5,不难发现一个特点我们可以以 B = sqrt(V) 为边界分两种方法讨论
①.如果 Y <= B
此时我们可以暴力枚举所有情况的答案,处理时间复杂度最多为 O(N*B),查询只需要 O(1)
②.如果 Y > B
此时如何处理呢?注意到我们只需要余数最小,那么我们可以往商的方向上想,如果直到商,那么余数也就出来了,所以我们可以考虑枚举商然后去二分第一个大于等于商的数,此时这个数的余数一定是所有相同商中的最小余数,时间复杂度为 O(N*B*logN),注意枚举商是 sqrt(V) 的复杂度
具体实现看代码
代码:
cpp
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define yes cout << "YES\n"
#define no cout << "NO\n"
mt19937 rnd(chrono::steady_clock::now().time_since_epoch().count());
const int B = 550;
// mod i 的最小结果
int ans[B];
void solve()
{
int n;
cin >> n;
set<int> has;
for (int i = 0; i < n; i++)
{
char c;
cin >> c;
if (c == 'A')
{
int x;
cin >> x;
for (int i = 1; i <= B; i++)
ans[i] = min(ans[i], x % i);
has.insert(x);
}
else
{
int y;
cin >> y;
if (y >= B)
{
int now = y;
//枚举商的结果,即枚举 ky,那么最接近的肯定是余数最小的,二分寻找即可
for (int i = 0; i <= 300000; i+=y)
{
auto it = has.lower_bound(i);
if(it == has.end()) break;
now = min(now,*it - i);
}
cout << now << endl;
}
else
cout << ans[y] << endl;
}
}
}
signed main()
{
memset(ans, 0x3f, sizeof ans);
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1;
while (t--)
{
solve();
}
return 0;
}