Silksong
笑点解析:模拟赛赛时想完前面全部最后一步糖糖统计不会做赫赫,但是丝之歌要发售了好耶。
先考虑序列情况。相当于求出所有区间
放到网格上,先
视实现时间复杂度
#include <bits/stdc++.h>
#define uint unsigned int
#define ull unsigned long long
#define LL long long
using namespace std;
const int N = 2.5e3 + 10;
int n, m, A[N][N], tmp[N]; LL Ans = 0;
int stk[N], tp;
void GetValidSegs(int* A, int n, vector<pair<int, int> >& res) {
stk[tp = 1] = 1;
for (int i = 2; i <= n; i ++) {
while (tp && A[stk[tp]] < A[i]) tp --;
if (tp && stk[tp] + 1 < i) res.push_back({stk[tp] + 1, i - 1});
stk[++ tp] = i;
}
stk[tp = 1] = n;
for (int i = n - 1; i >= 1; i --) {
while (tp && A[stk[tp]] < A[i]) tp --;
if (tp && stk[tp] - 1 > i && A[stk[tp]] != A[i]) res.push_back({i + 1, stk[tp] - 1});
stk[++ tp] = i;
} return ;
}
vector<int> col[N][N]; int lst[N][N], toki[N][N];
vector<pair<int, int> > ins[N]; vector<int> upd[N];
int tr[N], opt[N], len;
void add(int u, int k) { opt[++ len] = u; for (int i = u; i <= n; i += i & -i) tr[i] += k; }
int query(int u) { int r = 0; for (int i = u; i; i ^= i & -i) { r += tr[i]; } return r; }
void clear() {
for (int i = 1; i <= len; i ++) for (int j = opt[i]; j <= n; j += j & -j) tr[j] = 0;
len = 0; return ;
}
int main() {
freopen(".in", "r", stdin); freopen(".out", "w", stdout);
ios :: sync_with_stdio(0); cin.tie(0); cout.tie(0);
cin >> n >> m;
for (int i = 1; i <= n; i ++) for (int j = 1; j <= m; j ++) cin >> A[i][j];
for (int i = 1; i <= n; i ++) {
vector<pair<int, int> > vec; GetValidSegs(A[i], m, vec);
for (auto [l, r] : vec) col[l][r].push_back(i);
}
for (int i = 1; i <= n; i ++) for (int j = 1; j <= n; j ++) toki[i][j] = 250904;
for (int i = 1; i <= m; i ++) {
for (int j = 1; j <= n; j ++) tmp[j] = A[j][i];
vector<pair<int, int> > vec; GetValidSegs(tmp, n, vec);
for (auto [l, r] : vec) {
if (toki[l][r] != i - 1) lst[l][r] = i;
toki[l][r] = i; ins[lst[l][r]].push_back({l, r});
}
for (int j = 1; j <= i; j ++) {
for (auto [l, r] : ins[j]) upd[r].push_back(l);
int lft = -1, lst = -1;
for (int k : col[j][i]) {
if (lst != k - 1) {
if (lft != -1) Ans += query(n) - query(lft - 1);
lft = k;
} lst = k; for (int x : upd[k]) add(x, 1);
}
if (lft != -1) Ans += query(n) - query(lft - 1);
clear();
}
for (auto [l, r] : vec) ins[lst[l][r]].clear();
for (int j = 1; j <= n; j ++) upd[j].clear();
} cout << Ans << "\n";
return 0;
}