题意
给定一个 u , d , l , r u,d,l,r u,d,l,r 组成的字符串和一个01矩阵。玩家按照字符串方向移动,初始为0,经过格子染为1。问是否存在子串能绘制出给定矩阵。
题解
此题为二位01矩阵的hash方法,也叫做多项式hash。
h
a
s
h
=
∑
i
∑
j
p
1
i
×
p
2
j
×
[
d
[
i
]
[
j
]
=
1
]
hash = \sum_i \sum_j p_1^i\times p_2^j \times [d[i][j] =1]
hash=i∑j∑p1i×p2j×[d[i][j]=1]
这样可以支持快速
O
(
1
)
O(1)
O(1) 的实现上下左右的平移。
然后就可以用滑动窗口维护子串的位置,支持在前面增加一个元素,在后面删除一个元素即可。
代码
#include <bits/stdc++.h>
#define mem(f, v) memset(f,v,sizeof(f))
#define file(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout);
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 100010;
const int inf = ~(1u << 31u);
const ll linf = ~(1llu << 63u);
using namespace std;
const int mod = 1e9 + 7;
ll ppow(ll x, ll y) {
ll res = 1;
for (x %= mod; y; y >>= 1, x = x * x % mod)
if (y & 1) res = res * x % mod;
return res;
}
const int p1 = 3, p2 = 5;
struct mtxHash {
int num; // 当前覆盖数量,当前形状
map<pair<int, int>, int> mp; // 当前地图
queue<pair<int, int>> op_data; // 坐标x,坐标y
deque<pair<int, int>> row_num, col_num; // 坐标id,数量
vector<ll> mi1, mi2;
ll hash, inv_mi1, inv_mi2;
mtxHash() : num(1) {
mi1.resize(100001, 0);
mi1[0] = 1;
for (int i = 1; i <= 100000; i++) mi1[i] = mi1[i - 1] * p1 % mod;
mi2.resize(100001, 0);
mi2[0] = 1;
for (int i = 1; i <= 100000; i++) mi2[i] = mi2[i - 1] * p2 % mod;
inv_mi1 = ppow(p1, mod - 2);
inv_mi2 = ppow(p2, mod - 2);
mp[make_pair(0, 0)]++;
op_data.emplace(0, 0);
row_num.emplace_back(0, 1);
col_num.emplace_back(0, 1);
hash = 1;
}
int gt(int i, int j) { return mi1[i] * mi2[j] % mod; }
pair<ll, int> getHash(vector<string> &d) {
ll res = 0;
int nm = 0, x = 0, y = 0;
for (int i = 0; i < d.size(); i++) {
for (int j = 0; j < d[i].size(); j++) {
if (d[i][j] == 'X') goto la1;
}
x++;
}
la1:
for (int i = 0; i < d[0].size(); i++) {
for (int j = 0; j < d.size(); j++) {
if (d[j][i] == 'X') goto la2;
}
y++;
}
la2:
for (int i = x; i < d.size(); i++)
for (int j = y; j < d[i].size(); j++)
if (d[i][j] == 'X') {
res = (res + gt(i - x, j - y)) % mod;
nm++;
}
return make_pair(res, nm);
}
void add(char op) {
int nx, ny;
auto &org = op_data.back();
if (op == 'u') nx = org.first - 1, ny = org.second;
if (op == 'd') nx = org.first + 1, ny = org.second;
if (op == 'l') nx = org.first, ny = org.second - 1;
if (op == 'r') nx = org.first, ny = org.second + 1;
op_data.emplace(nx, ny);
int dx, dy;
if (nx < row_num.front().first) {
row_num.emplace_front(nx, 1);
dx = 0;
hash = (hash * mi1[1]) % mod;
} else if (nx > row_num.back().first) {
row_num.emplace_back(nx, 1);
dx = row_num.size() - 1;
} else {
row_num[nx - row_num.front().first].second++;
dx = nx - row_num.front().first;
}
if (ny < col_num.front().first) {
col_num.emplace_front(ny, 1);
dy = 0;
hash = (hash * mi2[1]) % mod;
} else if (ny > col_num.back().first) {
col_num.emplace_back(ny, 1);
dy = col_num.size() - 1;
} else {
col_num[ny - col_num.front().first].second++;
dy = ny - col_num.front().first;
}
auto &mp_now = mp[make_pair(nx, ny)];
if (mp_now == 0) {
num++;
hash = (hash + gt(dx, dy)) % mod;
}
mp_now++;
}
void del() {
auto xy = op_data.front();
op_data.pop();
int dx = xy.first - row_num.front().first;
int dy = xy.second - col_num.front().first;
auto &mp_now = mp[xy];
mp_now--;
if (mp_now == 0) {
num--;
hash = ((hash - gt(dx, dy)) % mod + mod) % mod;
}
row_num[dx].second--;
col_num[dy].second--;
if (row_num[dx].second == 0) {
if (dx == 0) {
row_num.pop_front();
hash = (hash * inv_mi1) % mod;
} else row_num.pop_back();
}
if (col_num[dy].second == 0) {
if (dy == 0) {
col_num.pop_front();
hash = (hash * inv_mi2) % mod;
} else col_num.pop_back();
}
}
};
int main() {
ios::sync_with_stdio(false);
file("easy");
int len;
cin >> len;
string input;
vector<pair<char, int>> str;
getline(cin, input);
getline(cin, input);
set<char> st = {'u', 'd', 'l', 'r'};
for (int i = 0; i < input.length(); i++) {
if (st.count(input[i])) {
// cout << input[i];
str.emplace_back(input[i], i + 1);
}
}
// cout << endl;
int n, m;
cin >> n >> m;
vector<string> mt(n);
for (auto &x:mt) cin >> x;
mtxHash ha;
auto tp = ha.getHash(mt);
ll val = tp.first;
int num_org = tp.second;
int r = 0;
for (int i = 0; i < str.size(); i++) {
while (r < str.size() && ha.num < num_org)
ha.add(str[r++].first);
if (ha.hash == val) {
cout << "YES\n";
cout << str[i].second << " " << str[r - 1].second << "\n";
return 0;
}
ha.del();
}
cout << "NO\n";
return 0;
}
/*
43
you should read statement really carefully.
3 6
.X....
.XX...
..XX..
43
you should read statement really carefully.
3 6
...XX.
..XXX.
...XXX
* */