[BalkanOI 2007] Cipher

我们需要在字符矩阵中统计所有可能的x行y列的子矩阵的出现次数,并找出出现次数最多的那个。
我们使用哈希来表示每个子矩阵。
计算每个子矩阵的哈希值。
使用双哈希来减少哈希冲突的可能性。
行哈希:预先计算每行的前缀哈希值,以便快速计算任意子串的哈希值。
列哈希:对于每个可能的列起始位置,计算所有行的子串哈希值,然后计算这些哈希值的列方向哈希值,从而得到整个子矩阵的哈希值。
使用哈希值对来统计每个子矩阵的出现次数,最后找出出现次数最多的子矩阵的次数。
码风经过ai调试

#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <algorithm>
using namespace std;
 
typedef long long ll;
 
const ll base1 = 131;
const ll base2 = 13331;
const ll base3 = 13131;
const ll base4 = 13331;
const ll mod1 = 1e9+7;
const ll mod2 = 1e9+9;
 
int main() {
    int n, m;
    cin >> n >> m;
    char** s = new char*[n+1];
    for (int i = 0; i <= n; i++) s[i] = new char[m+1];
    for (int i = 1; i <= n; i++) {
        string line;
        getline(cin, line);
        for (int j = 1; j <= m; j++) {
            s[i][j] = line[j-1];
        }
    }
    int x, y;
    cin >> x >> y;
    int max_nm = max(n, m) + 10;
    ll* pow1 = new ll[max_nm];
    ll* pow2 = new ll[max_nm];
    ll* pow3 = new ll[max_nm];
    ll* pow4 = new ll[max_nm];
    pow1[0] = 1;
    pow2[0] = 1;
    pow3[0] = 1;
    pow4[0] = 1;
    for (int i = 1; i < max_nm; i++) {
        pow1[i] = (pow1[i-1] * base1) % mod1;
        pow2[i] = (pow2[i-1] * base2) % mod2;
        pow3[i] = (pow3[i-1] * base3) % mod1;
        pow4[i] = (pow4[i-1] * base4) % mod2;
    }
    ll** h1 = new ll*[n+1];
    ll** h2 = new ll*[n+1];
    for (int i = 0; i <= n; i++) {
        h1[i] = new ll[m+1];
        h2[i] = new ll[m+1];
    }
    for (int i = 1; i <= n; i++) {
        h1[i][0] = 0;
        h2[i][0] = 0;
        for (int j = 1; j <= m; j++) {
            h1[i][j] = (h1[i][j-1] * base1 + s[i][j]) % mod1;
            h2[i][j] = (h2[i][j-1] * base2 + s[i][j]) % mod2;
        }
    }
    map<pair<ll, ll>, int> count_map;
    ll max_count = 0;
    pair<ll, ll> max_hash;
    for (int j = 1; j <= m - y + 1; j++) {
        vector<ll> A1(n+1), A2(n+1);
        for (int i = 1; i <= n; i++) {
            A1[i] = (h1[i][j+y-1] - h1[i][j-1] * pow1[y] % mod1 + mod1) % mod1;
            A2[i] = (h2[i][j+y-1] - h2[i][j-1] * pow2[y] % mod2 + mod2) % mod2;
        }
        vector<ll> col1(n+1), col2(n+1);
        col1[0] = 0;
        col2[0] = 0;
        for (int i = 1; i <= n; i++) {
            col1[i] = (col1[i-1] * base3 + A1[i]) % mod1;
            col2[i] = (col2[i-1] * base4 + A2[i]) % mod2;
        }
        for (int i = 1; i <= n - x + 1; i++) {
            ll H1 = (col1[i+x-1] - col1[i-1] * pow3[x] % mod1 + mod1) % mod1;
            ll H2 = (col2[i+x-1] - col2[i-1] * pow4[x] % mod2 + mod2) % mod2;
            pair<ll, ll> key = {H1, H2};
            count_map[key]++;
            if (count_map[key] > max_count) {
                max_count = count_map[key];
                max_hash = key;
            }
        }
    }
    vector<pair<int, int>> positions;
    vector<string> content;
    bool content_recorded = false;
    for (int j = 1; j <= m - y + 1; j++) {
        vector<ll> A1(n+1), A2(n+1);
        for (int i = 1; i <= n; i++) {
            A1[i] = (h1[i][j+y-1] - h1[i][j-1] * pow1[y] % mod1 + mod1) % mod1;
            A2[i] = (h2[i][j+y-1] - h2[i][j-1] * pow2[y] % mod2 + mod2) % mod2;
        }
        vector<ll> col1(n+1), col2(n+1);
        col1[0] = 0;
        col2[0] = 0;
        for (int i = 1; i <= n; i++) {
            col1[i] = (col1[i-1] * base3 + A1[i]) % mod1;
            col2[i] = (col2[i-1] * base4 + A2[i]) % mod2;
        }
        for (int i = 1; i <= n - x + 1; i++) {
            ll H1 = (col1[i+x-1] - col1[i-1] * pow3[x] % mod1 + mod1) % mod1;
            ll H2 = (col2[i+x-1] - col2[i-1] * pow4[x] % mod2 + mod2) % mod2;
            if (H1 == max_hash.first && H2 == max_hash.second) {
                positions.push_back({i, j});
                if (!content_recorded) {
                    for (int r = i; r < i + x; r++) {
                        string line = "";
                        for (int c = j; c < j + y; c++) {
                            line += s[r][c];
                        }
                        content.push_back(line);
                    }
                    content_recorded = true;
                }
            }
        }
    }
 
    cout << x << " " << y << endl;
    for (const string& line : content) {
        cout << line << endl;
    }
    cout << positions.size() << endl;
    sort(positions.begin(),positions.end());
    for (const auto& p : positions) {
        cout << p.first << " " << p.second << endl;
    }
}
posted @ 2025-08-21 19:25  zhuoheng  阅读(11)  评论(0)    收藏  举报