【二维差分】ICPC南京 A

https://codeforces.com/gym/104128/problem/A

题意

 

思路

二维差分+经典模型

考虑如果没有洞那么经历操作之后会剩下什么样子的袋鼠。发现上下左右移动可以看成是边界在移动,边界一直保持一个原初的矩形形状,而且上下移动和左右移动没有任何关系。一旦边界移动到了一个位置,这个位置前面的袋鼠都会消失。

所以记录u,d,l,r,表示在移动时所产生的最小矩阵的上下左右边界,这样剩下的袋鼠数量就是有(d-u+1)*(r-l+1)个。

加入有洞的情况,发现洞产生的路径都可以通过平移获得,那么就只维护一条路径,就是从(0,0)点开始的路径,那么所有的点(i,j)的路径就是(0,0)点开始的路径上的点加(i,j)。 那么我们要维护有洞会让袋鼠消失多少,只有在u<=x<=d,l<=y<=r的才是有效被消失的袋鼠,那么就维护mp[i][j]表示从(i,j)点开始会让多少只袋鼠消失,发现对于点(x,y),只会对一个矩形内的数加1,左上角为(u-x,l-y),右下角为(d-x,r-y)的矩形,变成二维差分维护,那么在二维差分中给一个点加1等于给它往右往下的全部点加1.

注意:要去除经过的重复的点,重复点不能重复计算答案,因为他们去除的是同一片袋鼠。

Code:

#include <bits/stdc++.h>

constexpr int N = 1e3 + 10;
constexpr int mod = 998244353;
constexpr int Inf = 0x3f3f3f3f;

std::string s;

int n, m, k;
int f[N][N];
int vis[N][N];

void add(int x1, int y1, int x2, int y2) {
	f[x1][y1] ++;
	f[x2 + 1][y1] --;
	f[x1][y2 + 1] --;
	f[x2 + 1][y2 + 1] ++;
}
void solve() {
	std::cin >> n >> m >> k;
	for (int i = 0; i <= n + 5; i ++) {
		for (int j = 0; j <= m + 5; j ++) {
			vis[i][j] = f[i][j] = 0;
		}
	}
	std::cin >> s;
	int sz = s.size();
	s = " " + s;
	int u = 1, d = n, l = 1, r = m;
	int U = 1, D = n, L = 1, R = m;
	for (int i = 1; i <= sz; i ++) {
		if (s[i] == 'U') {
			u ++;
			d ++;
		}else if (s[i] == 'D') {
			u --;
			d --;
		}else if (s[i] == 'L') {
			l ++;
			r ++;
		}else {
			l --;
			r --;
		}
		U = std::max(U, u);
		D = std::min(D, d);
		L = std::max(L, l);
		R = std::min(R, r);
	}
	if (L > R || U > D) {
		if (k) {
			std::cout << 0 << "\n";
		}else {
			std::cout << n * m << "\n";
		}
		return;
	}
	int del = (R - L + 1) * (D - U + 1) - k;
	if (del < 0) {
		std::cout << 0 << "\n";
		return;
	}
	add(U, L, D, R);
	vis[L][U] = 1;
	for (int i = 1; i <= sz; i ++) {
		if (s[i] == 'L') {
			L --;
			R --;
		}else if (s[i] == 'R') {
			L ++;
			R ++;
		}else if (s[i] == 'U') {
			U --;
			D --;
		}else {
			U ++;
			D ++;
		}
		if (vis[L][U]) continue;
		vis[L][U] = 1;
		add(U, L, D, R);
	}
	for (int i = 1; i <= n; i ++) {
		for (int j = 1; j <= m; j ++) {
			f[i][j] += f[i - 1][j] + f[i][j - 1] - f[i - 1][j - 1];
		}
	}
	int ans = 0;
	for (int i = 1; i <= n; i ++) {
		for (int j = 1; j <= m; j ++) {
			if (f[i][j] == del) ans ++;
		}
	}
	std::cout << ans << "\n";
}
signed main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);

	int t = 1;
	std::cin >> t;
	while (t--) {
		solve();
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值