【LOJ3179】「IOI2019」視覺程序

【題目鏈接】

【思路要點】

  • 考慮 K=1K=1 的情況,我們需要判斷是否存在相鄰的黑色像素。
  • 如果我們知道兩個黑色像素的相對方向,則可以採取如下策略:
  • 不妨令兩個黑色像素在同一列,計算每一行的 oror ,並計算得到的數組的前綴 oror 與後綴 oror ,記爲 prei,sufipre_i,suf_i 。若存在一個 ii 使得 prei&sufi+2pre_i\&suf_{i+2}11 ,則說明兩個黑色像素所在的行相距至少爲 22 ,從而可以判斷它們是否相鄰。
  • 在不知道兩個黑色像素的相對方向時,可以採取如下策略:
  • 若將座標系進行旋轉 (x,y)(xy,x+y)(x,y)\rightarrow(x-y,x+y) ,則可以將兩個點 (x,y),(a,b)(x,y),(a,b) 的曼哈頓距離 xa+yb|x-a|+|y-b| 轉化爲切比雪夫距離 max{xa,yb}\max\{|x-a|,|y-b|\} ,從而在兩維座標上都進行上文的判斷即可。
  • 注意到上面的過程本質上判斷了兩個黑色像素的距離是否 K+1\geq K+1 ,那麼再判斷一下兩個黑色像素的距離是否 K\geq K 就行了。
  • N,MN,M 同階,時間複雜度 O(N2)O(N^2) ,使用操作次數 O(N)O(N) ,涉及元素個數 O(N2)O(N^2)
  • 以下代碼沒有考慮一些可能的對操作次數的常數優化。

【代碼】

#include "vision.h"
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 405;
int num[MAXN][MAXN], tot;
int pre[MAXN], suf[MAXN];
int getbool(int n, int m, int k) {
	for (int i = 2; i <= n + m; i++) {
		vector <int> opt; opt.clear();
		for (int j = 1; j <= n; j++) {
			int k = i - j;
			if (k >= 1 && k <= m) opt.push_back(num[j][k]);
		}
		if (i != 2) opt.push_back(pre[i - 1]);
		pre[i] = add_or(opt);
	}
	for (int i = n + m; i >= 2; i--) {
		vector <int> opt; opt.clear();
		for (int j = 1; j <= n; j++) {
			int k = i - j;
			if (k >= 1 && k <= m) opt.push_back(num[j][k]);
		}
		if (i != n + m) opt.push_back(suf[i + 1]);
		suf[i] = add_or(opt);
	}
	vector <int> opt; opt.clear();
	for (int i = 2, j = i + k; j <= n + m; i++, j++) {
		vector <int> tmp; tmp.clear();
		tmp.push_back(pre[i]), tmp.push_back(suf[j]);
		opt.push_back(add_and(tmp));
	}
	int resa = add_or(opt);
	for (int i = 1; i <= n; i++)
	for (int j = 1, k = m; j <= k; j++, k--)
		swap(num[i][j], num[i][k]);
	
	for (int i = 2; i <= n + m; i++) {
		vector <int> opt; opt.clear();
		for (int j = 1; j <= n; j++) {
			int k = i - j;
			if (k >= 1 && k <= m) opt.push_back(num[j][k]);
		}
		if (i != 2) opt.push_back(pre[i - 1]);
		pre[i] = add_or(opt);
	}
	for (int i = n + m; i >= 2; i--) {
		vector <int> opt; opt.clear();
		for (int j = 1; j <= n; j++) {
			int k = i - j;
			if (k >= 1 && k <= m) opt.push_back(num[j][k]);
		}
		if (i != n + m) opt.push_back(suf[i + 1]);
		suf[i] = add_or(opt);
	}
	opt.clear();
	for (int i = 2, j = i + k; j <= n + m; i++, j++) {
		vector <int> tmp; tmp.clear();
		tmp.push_back(pre[i]), tmp.push_back(suf[j]);
		opt.push_back(add_and(tmp));
	}
	int resb = add_or(opt);
	for (int i = 1; i <= n; i++)
	for (int j = 1, k = m; j <= k; j++, k--)
		swap(num[i][j], num[i][k]);
	opt.clear();
	opt.push_back(resa), opt.push_back(resb);
	return add_or(opt);
}
void construct_network(int n, int m, int k) {
	for (int i = 1; i <= n; i++)
	for (int j = 1; j <= m; j++)
		num[i][j] = tot++;
	if (k == n + m - 2) {
		getbool(n, m, k);
		return;
	}
	int greater = getbool(n, m, k + 1);
	int geq = getbool(n, m, k);
	int ngr = add_not(greater);
	vector <int> opt; opt.clear();
	opt.push_back(geq), opt.push_back(ngr);
	add_and(opt);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章