abc179f
大意
给定一个 (n*n) 的棋盘,中间 ((n-2)*(n-2)) 的区域有黑色棋子。右边缘和下边缘总共长度为 (2n-1) 的区域有白色棋子。
有如下操作:
((1,x)) 表示从 ((1,x)) 开始向下延伸,将所经过的黑色棋子变为白色,直到遇到第一个白色棋子停下。
((2,x)) 表示从 ((x,1)) 开始向右延伸,将所经过的黑色棋子变为白色,直到遇到第一个白色棋子停下。
((2leq x leq n-1))
问,进行q次给定操作后,黑色棋子有多少个(保证任意操作不重复)。
思路
比前两道题简单...
记 (s_1) 为当前所有 ((1,x)) 中 (x) 的最小值, (s_2) 同理记为另一种操作的最小值。
记 (A) 为之前所有的 (s_1) 值组成的序列, (B) 同理。
记 (C) 为之前 (A) 加入新元素时加入的一个特殊值组成的序列, (D) 同理。
假设本次操作为 ((1,x))
若 (x < s_1) ,不难发现,会有 ((s_2-2)) 个棋子变为白色,因为形成 (s_2) 的操作形成了一道横屏障,仅有 ((2,s_2-1)) 的棋子可以被选择 。
其实,该步操作之后,对于所有 ((1,x_i) ; x < x_i < s_1) 其能选择的黑色棋子数一定是 ((s_2-2)) ,因为选择 (x) 的操作形成了一道竖屏障。
所以我们在 (A) 中添加 (s_1) ,在 (C) 中添加 ((s_2-2)) ,并更新 (s_1 = x)。
若 (x > s_1) ,显然,按上述操作 (A) 一定是一个单调递减序列,且 (A,B) 中一一对应。
所以考虑在 (A) 中二分 (x) 。
对于另一种操作,思路与这种操作并无不同。
细节也是不少的...
代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
#define ll long long
#define ull unsigned long long
#define cint const int&
#define Pi acos(-1)
const int mod = 998244353;
const int inf_int = 0x7fffffff;
const ll inf_ll = 0x7fffffffffffffff;
const double ept = 1e-9;
ll n, q;
int qu[2][200200], cnt[2];
int num[2][200200];
int main() {
cin >> n >> q;
ll ans = (n-2) * (n-2);
int a, x;
ll s[2] = {n, n};
for(int i=1; i<=q; i++) {
cin >> a >> x;
a--;
int key = upper_bound(qu[a]+1, qu[a]+cnt[a]+1, x, greater< int >()) - qu[a];
if(key > cnt[a]) {
ans -= (s[a^1]-2);
s[a] = x;
qu[a][++cnt[a]] = x;
num[a][cnt[a]] = s[a^1] - 2;
} else ans -= num[a][key];
}
cout << ans;
return 0;
}