CodeForces-846Dの監視(2次元プレフィックスと+ 2ポイント)

最近、ルバはモニターを購入しました。モニターは、サイズn×mの長方形の行列です。しかし、その後、彼女はいくつかのピクセルが適切に機能しなくなることに気づき始めました。ルバは、モニターが完全に壊れたピクセルで構成される正方形のk×kを含むとき、モニターが最初に壊れると考えています。彼女は、qピクセルがすでに壊れていることを知っており、それぞれについて、それが機能しなくなった瞬間を知っています。Lubaがモニターが壊れた時期を判断するのを手伝ってください(または、すべてのqピクセルが機能しなくなった後もモニターが壊れていないことを伝えてください)。

入力
最初の行には、4つの整数n、m、k、q(1≤n、m≤500、1≤k≤min(n、m)、0≤q≤n・m)が含まれています—の長さと幅モニター、このサイズの壊れた長方形がある場合にモニターが壊れたような長方形のサイズ、および壊れたピクセルの数。

次のq行のそれぞれには、3つの整数xi、yi、ti(1≤xi≤n、1≤yi≤m、0≤t≤109)— i番目の壊れたピクセル(行列内の行と列)の座標とそれが機能しなくなった瞬間。各ピクセルは最大で1回リストされます。

ピクセルはモーメントtiですでに壊れていると考えます。

出力
1つの数値を印刷します—モニターが壊れた最小の瞬間、またはこれらのqピクセルが機能しなくなった後も壊れていない場合は「-1」。


インプット
2 3 2 5
2 1 8
2 2 8
1 2 1
1 3 4
2 3 2
出力
8
入力
3 3 2 5
1 2 2
2 2 1
2 3 5
3 2 10
2 1 100
出力
-1

2次元の接頭辞と
意味:
n×mの行列が与えられると、その中のq個の点が壊れます。行列全体のk×kの部分行列のすべての点が壊れると、行列全体が破損します。q点は時系列で破損しており、マトリックス全体が破損している、つまりk×kサブ行列の点がすべて破損していると判断されます。行列全体に損傷がない場合は、-1を出力します。
問題解決のアイデア:
各ポイントが損傷した時間を考えると、時間は線形で単調であり、2分割時間を使用して時間の複雑さを軽減できます。
まず、q個のポイントを小さいものから大きいものへと時系列で並べ替え、時間を2つに分割します。各時間midについて、2次元配列mpを使用して、中間時間内に損傷したすべてのポイントを1ずつ累積し、次に1を加算します。配列aにプレフィックスの合計を再度検索し、次にアレイaのプレフィックスの合計を検索し、最後にグラフ全体でk×kサブマトリックスを列挙し、サブマトリックス内の損傷したポイントの数をクエリします。数がk×kに等しい場合、midが実行可能です。

ACコード:
PS:qのデータ範囲はn * mであることに注意してください

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cctype>
#include<iomanip>
#include<map>
#include<vector>
#include<list>
#include<deque>
#include<stack>
#include<queue>
#include<set>
#include<cctype>
#include<string>
#include<stdexcept>
#include<fstream>
#define mem(a,b) memset(a,b,sizeof(a))
#define debug() puts("what the fuck!")
#define debug(a) cout<<#a<<"="<<a<<endl;
#define speed {
    
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); };
#define ll long long
#define mod 998244353
using namespace std;
const double PI = acos(-1.0);
const int maxn = 5e2 + 10;
const int INF = 0x3f3f3f3f;
const double esp_0 = 1e-6;
ll gcd(ll x, ll y) {
    
    
	return y ? gcd(y, x % y) : x;
}
ll lcm(ll x, ll y) {
    
    
	return x * y / gcd(x, y);
}
ll extends_gcd(ll a, ll b, ll& x, ll& y) {
    
    
	if (b == 0) {
    
    
		x = 1;
		y = 0;
		return a;
	}
	ll gcdd=extends_gcd(b, a % b, x, y);
	ll temp = x;
	x = y;
	y = temp - (a / b) * y;
	return gcdd;
}
struct node {
    
    
	int x, y, t;
	friend bool operator<(const node& a, const node& b) {
    
    
		return a.t < b.t;
	}
}a[maxn * maxn];
int mp[maxn][maxn];
int sum[maxn][maxn];
int n, m, k, q;
int judge(int time) {
    
    
	mem(mp, 0);
	mem(sum, 0);
	for (int i = 0; i < q; ++i) {
    
    
		if (a[i].t <= time)mp[a[i].x][a[i].y] = 1;
	}
	for (int i = 1; i <= n; ++i) {
    
    
		for (int j = 1; j <= m; ++j) {
    
    
			sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + mp[i][j];//求二维前缀和
		}
	}
	for (int i = k; i <= n; ++i) {
    
    
		for (int j = k; j <= m; ++j) {
    
    
		//判断每一个k*k的子矩阵,注意下标是K
			if (sum[i][j] - sum[i - k][j] - sum[i][j - k] + sum[i - k][j - k] == k * k) {
    
    
				return 1;
			}
		}
	}
	return 0;
}
int main(){
    
    
	scanf("%d%d%d%d", &n, &m, &k, &q);
	int left = 0, right = 0, mid = 0;
	for (int i = 0; i < q; ++i) {
    
    
		scanf("%d%d%d", &a[i].x, &a[i].y, &a[i].t);
		right = max(right, a[i].t);
	}
	sort(a, a + q);
	int ans = INF;
	while (left <= right) {
    
    
		mid = (left + right) >> 1;
		if (judge(mid)) {
    
    
			ans = mid;
			right = mid - 1;
		}
		else
			left = mid + 1;
	}
	if (ans == INF) {
    
    
		ans = -1;
	}
	printf("%d\n", ans);
	return 0;
}

おすすめ

転載: blog.csdn.net/qq_40924271/article/details/109911905