[题目]
(https://marsoj.cn/p/P2139)
1000ms 256MiB
说明
我们有一个N个元素的序列A=(a1,a2,...,aN)
然后进行如下Q次询问:
对于第i次询问:给你一对整数(xi,ki) ,现在从左到右挨个从序列A中查找元素xi,找到xi出现恰好ki次的当下下标,或者输出-1,表示不存在该下标。
输入格式
第一行输入N和Q
第二行输入序列A
对于接下来的Q行,每行输入一对整数(xi,ki)
输出格式
对于第i次询问:给你一对整数(xi,ki) ,从左到右挨个从序列A中查找元素xi,找到xi出现恰好ki次的当下下标,或者输出-1,表示不存在该下标。
样例
输入数据 1
6 8
1 1 2 3 1 2
1 1
1 2
1 3
1 4
2 1
2 2
2 3
4 1
输出数据 1
1
2
5
-1
3
6
-1
-1
提示
【样例解释 #1】
1出现在1,2,5三个位置
【数据规模与约定】
对于80%的数据保证1<=N<=104,1<=Q<=104
对于100%的数据保证1<=N<=2105,1<=Q<=2105,0<=ai<=109,0<=xi<=109,1<=ki<=N
TLE95pts
#include <bits/stdc++.h>
#define long long int
#define N 200000+10
#pragma GCC optimize(3,"Ofast","inline")
using namespace std;
int n,q;
int a[N];
signed main()
{
// freopen("god.in", "r", stdin);
// freopen("god.out", "w", stdout);
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>q;
for(int i=1; i<=n; i++) {
cin>>a[i];
}
while(q--) {
int x,k;
bool flag=false;
cin>>x>>k;
int xb=0;
for(int i=1; i<=n; i++) {
if(a[i]==x) {
xb++;
if(xb==k) {
cout<<i<<'\n';
flag=true;
break;
}
}
}
if(!flag)
{
cout<<-1<<'\n';
}
}
return 0;
}
帮你问了下AI:
你的代码由于需要对每个查询遍历整个数组,复杂度达到了 O(N⋅Q),在数据范围较大时容易超时。优化的思路是通过预处理加速查询,将每个数在数组中的所有出现位置提前存储起来,这样每次查询时只需 O(logK)(使用二分查找)或 O(1)(直接索引),从而大幅降低复杂度。
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 200000 + 10;
int n, q;
vector<int> pos[N]; // 用于存储每个数字的出现位置
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n >> q;
vector<int> a(n + 1);
for (int i = 1; i <= n; ++i) {
cin >> a[i];
pos[a[i]].push_back(i); // 将每个数字出现的位置存入对应的向量
}
while (q--) {
int x, k;
cin >> x >> k;
if (pos[x].size() >= k) {
cout << pos[x][k - 1] << '\n'; // k-1是因为向量索引从0开始
} else {
cout << -1 << '\n';
}
}
return 0;
}
感谢dalao
时间复杂度就不对。你与处理一下每个值出现的所有位置,$O(1)$ 查询。
$a_i$ 比较大,可以用 map 或者离散化一下。每个值的出现位置可以用 vector 存。