http://codeforces.com/gym/103104

I. Sequence

题意:mm 个限制条件:pindexvaluep_{index}\neq value。问有多少个四元组 (A,B,L,R)(A,B,L,R) 满足 i[A,B]\forall i\in [A,B]pip_i 可以取 [L,R][L,R] 中任意数。1A,B,L,RN1 \le A,B,L,R \le N

单调栈

问题转化为二维网格上有 mm 个坏点,问有几个只包含好点的矩形。

dp[i][j]dp[i][j] 表示以 (i,j)(i,j) 为右下端点的矩形的个数。

遍历行,遍历列,对每一行维护一个递增的单调栈,左上端点的取法等于栈顶的左上位置取法数+当前位置到栈顶位置构成的矩形中的点数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <bits/stdc++.h>

bool dbg = true;
#define debug(x) if (dbg) cout << #x << ":\t" << (x) << endl;
using namespace std;
#define ll long long
#define ull unsigned ll
const int N = 5005;
const int INF = 0x3f3f3f3f;
const ll inf = 0x3f3f3f3f3f3f3f3f;
const ll mod = 1e9 + 7;
const ll inv2 = (mod + 1) / 2;
typedef pair<int, int> pii;
typedef pair<int, ll> pil;

int n, m;
int mz[N][N];
int a[N];
int st[N], tp;
int dp[N][N];

int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)for (int j = 1; j <= n; j++)mz[i][j] = 1;
for (int i = 1; i <= m; i++) {
int x, y;
scanf("%d%d", &x, &y);
mz[x][y] = 0;
}
ll ans = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++)
if (!mz[i][j])a[j] = 0;
else a[j]++;
tp = 0;
for (int j = 1; j <= n; j++) {
while (tp && a[st[tp]] > a[j])tp--;
if (tp)dp[i][j] = dp[i][st[tp]];
dp[i][j] += (j - st[tp]) * a[j];
ans += dp[i][j];
st[++tp] = j;
}
}
printf("%lld\n", ans);
return 0;
}