【Gym 101142】(NEERC 16)E Easy Reading

文章目录

题意

给定一个 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=ijp1i×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
 * */
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值