洛谷 CF701B

    科技2025-12-25  8

    题目链接

    题目大意

    这里有一个n*n的棋盘,然后给出m次操作(xi, yi),每次操作会将经过(xi, yi)的点所在的行和列覆盖,最后输出每一次操作后剩余没有被覆盖的棋盘上的格子数。

    初步思路

    这很像一道矩阵覆盖问题,但是这次是一个十字覆盖,那么我们来看下这个和矩阵覆盖有什么共同点。首先一个十字架可以分解成两个有一条边为1,剩下那条边为n(拿个小本本记下来) 的两个矩阵,那么我们就可以把这个十字覆盖分解成水平方向的特殊矩阵覆盖,和竖直方向的特殊矩阵覆盖,那我们在计算的时候是不是就可以直接算水平方向上有多少个位置不同的矩阵和竖直方向上有多少个位置不同的矩阵,然后在直接计算就好了。

    计算方法,假设水平方向有a个位置不同的矩阵,竖直方向有b个位置不同的矩阵,那答案应该就是 n*n - (a+b)n + ab (整个棋盘的格子数-(行数+列数)✖ 每行的个数+行列相交的格子数)

    上代码!!!

    #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<queue> #include<map> #define ll long long #define pi acos(-1) #define inf 0x3f3f3f3f #define pii pair<int, int> #define fi first #define se second #define mp(a, b) make_pair(a, b) #define piii pair<pii, int> #define uf(a, b, i) for (register int i = (a); i <= (b); ++i) #define df(a, b, i) for (register int i = (a); i >= (b); --i) using namespace std; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } template<class T> inline void print(T x) { if(x > 9) print(x/10); putchar(x%10 + '0'); } template<class T> T Max(T a, T b) { return a > b ? a : b; } template<class T> T Min(T a, T b) { return a < b ? a : b; } const ll mod = 1e9 + 7; int n, m; ll ans; int cnt[2]; bool vis[100005][2]; pii p[100005]; void scan() { n = read(); m = read(); uf (1, m, i) { p[i].fi = read(); p[i].se = read(); } } void work() { uf (1, m, i) { if (!vis[p[i].fi][0]) cnt[0]++, vis[p[i].fi][0] = 1; if (!vis[p[i].se][1]) cnt[1]++, vis[p[i].se][1] = 1; ans = 1ll*n*n - 1ll*(cnt[0]+cnt[1])*n + 1ll*cnt[0]*cnt[1]; print(ans); putchar(' '); } } int main() { scan(); work(); return 0; }
    Processed: 0.016, SQL: 9