题意:一个矩阵,A[I][J]=lcm(i,j),求所有k*k矩阵的最大值的和
求lcm矩阵有两种方法:
一种是官方题解的方法(打表?蒟蒻不太清楚叫什么):
运行时间:
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (!gcd_rix[i][j]) {
for (int k = 1; k * i <= n && k * j <= m; k++) {
gcd_rix[k * i][k * j] = k;
max_gcd[k * i][k * j] = k * i * j;
}
}
}
}
还有一种自然就是暴力了(勉强能过):
运行时间
int gcd(int a,int b) {
while (b) {
int c = a % b;
a = b;
b = c;
gcd(a,b);
}
return a;
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
max_gcd[i][j] = i * j / gcd(i, j);
}
}
上面都不是重点,重点是下面求解最大值和。我们先求解每一行从第j列到j-k+1列的最大值,然后在求解从第i行到底i+k-1行的最大值,进行上述两次操作后,得到的是第i行第j列到底i+k-1行j+k-1列的最大值。维护行/列最大值可以用单调队列维护。
AC代码(暴力版)
#include<cstdio>
#include <iostream>
#include <cstring>
#include <deque>
#include<cmath>
using namespace std;
const int N = 5005;
int gcd_rix[N][N];
int max_gcd[N][N];
int gcd(int a,int b) {
while (b) {
int c = a % b;
a = b;
b = c;
gcd(a,b);
}
return a;
}
int main() {
int n, m, v;
scanf("%d %d %d", &n, &m, &v);
int t = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
max_gcd[i][j] = i * j / gcd(i, j);
}
}
for (int i = 1; i <= n; i++) {
deque<int> dq;
for (int j = 1; j <= m; j++) {
while (!dq.empty() && max_gcd[i][dq.back()] < max_gcd[i][j]) dq.pop_back();
while (!dq.empty() && j - dq.front() >= v) dq.pop_front();
dq.push_back(j);
max_gcd[i][j] = max_gcd[i][dq.front()];
}
}
long long ans = 0;
for (int i = 1; i <= m; i++) {
deque<int> dq;
for (int j = 1; j <= n; j++) {
while (!dq.empty() && max_gcd[dq.back()][i] < max_gcd[j][i]) dq.pop_back();
while (!dq.empty() && j - dq.front() >= v) dq.pop_front();
dq.push_back(j);
max_gcd[j][i] = max_gcd[dq.front()][i];
if (j >= v && i >= v) ans = (ans+ max_gcd[j][i]);
}
}
printf("%lld\n", ans);
}