本文共 2063 字,大约阅读时间需要 6 分钟。
我们面临一个挑战性问题:给定一个1000×1000的矩阵,保证元素互不相同,并接受2e5次查询。每次查询给出两个数x和y,要求找出满足以下条件的点(a, b)的数量:
由于矩阵规模较大(1000×1000),暴力解法显然不可行。直接暴力每次查询需要遍历整个矩阵,时间复杂度为O(n^2),对于q=2e5次查询,总时间复杂度将达到O(2e5 * 1e6) = 2e11,这远远超出了可接受的范围。
为了应对如此多的查询,我们需要对所有可能的情况进行预处理,这样每次查询都可以在O(1)时间内得到结果。
行和列的排序:
二分查找:
行排序:
列排序:
预处理结果存储:
Answer,其中Answer[x][y]存储满足条件的点(a, b)的数量。这样,每次查询只需从预处理结果中直接获取即可。预处理的主要工作包括:
对每一行和每一列进行排序:时间复杂度为O(n log n + m log m),其中n和m分别为矩阵的行数和列数。
对每一对(x, y)进行预处理:由于矩阵为1000×1000,预处理总共有1e6次操作,每次操作包括两次二分查找(行和列的位置确定),因此总时间复杂度为O(n^2 log n)。
预处理完成后,每次查询的时间复杂度为O(1),因为查询只需要从预处理结果中直接获取。
#include#include #include #include #include using namespace std;const int N = 1010;#define Rep(i, a, b) for(int i = a; i <= b; i++)#define LL long longint A[N][N], B[N][N];int Sa[N][N], Sb[N][N];int Answer[N][N];int n, m, q;int main() { // 读取输入 Rep(i, 1, n) Rep(j, 1, m) A[i][j] = read(); Rep(i, 1, m) Rep(j, 1, n) B[i][j] = A[j][i]; // 预处理每一行和每一列 Rep(i, 1, n) sort(Sa[i] + 1, Sa[i] + m + 1); Rep(i, 1, m) sort(Sb[i] + 1, Sb[i] + n + 1); // 预处理所有可能的查询 Rep(i, 1, n) Rep(j, 1, m) { int Num = A[i][j]; int x = lower_bound(Sa[i] + 1, Sa[i] + m + 1, Num) - Sa[i]; int y = lower_bound(Sb[j] + 1, Sb[j] + n + 1, Num) - Sb[j]; int xx = m - x + 1, yy = n - y + 1; Answer[xx][yy]++; } // 处理查询 Rep(i, 1, q) { int x = read(), y = read(); printf("%d\n", Answer[x][y]); } return 0;}
预处理时间:
查询速度:
通过预处理技术,我们将原本需要O(q * n^2)时间的查询复杂度降低到O(n^2 log n + q),显著提升了整体效率。这一方法在处理大规模数据时非常有效,对于类似的问题具有广泛的应用价值。
转载地址:http://jojfk.baihongyu.com/