【题解】[COCI2020-2021#3] Sateliti

solution:

核心考点是字符串排序。码量较大。

总的情况显然最多有 n m nm nm 种,通过二维散列比较子矩阵可以达到 l o g n + l o g m logn+logm logn+logm ,所以直接暴力枚举 + 比较大小即可。难点在比较大小的方法,我们设 p [ i ] [ j ] = a [ i ] [ j ] ∗ 5 i 3 j p[i][j]=a[i][j]*5^i3^j p[i][j]=a[i][j]5i3j h a s ( i , j , i 2 , j 2 ) = ∑ l 1 = i i 2 ∑ l 2 = j j 2 p [ l 1 ] [ l 2 ] has(i,j,i2,j2)=\sum_{l1=i}^{i2}\sum_{l2=j}^{j2}p[l1][l2] has(i,j,i2,j2)=l1=ii2l2=jj2p[l1][l2]。这样前缀和可以方便地减去贡献。时间复杂度 O ( n m ( l o g n + l o g m ) ) O(nm(logn+logm)) O(nm(logn+logm))

#include <cstdio> #include <cmath> #include <algorithm> #include <bitset> #define PII pair<int,int> #define ll long long #define ull unsigned long long using namespace std; const int mx = 2005, P = 5, Q = 3; int n, m; char s[mx][mx]; ull p[mx][mx], h[mx][mx]; ull has(int i, int j, int i2, int j2) { return (h[i + i2][j + j2] - h[i][j + j2] - h[i + i2][j] + h[i][j]); } bool equal(int x, int y, int x2, int y2, int x3, int y3) { return has(x, y, x3, y3) * p[x2][y2] == has(x2, y2, x3, y3) * p[x][y]; } int main() { // freopen("data.in","r",stdin); scanf("%d%d", &n, &m); for (int i = 0; i < n; i++) { scanf("%s", s[i]); } for (int i = 0; i < n << 1; i++) { for (int j = 0; j < m << 1; j++) { if (i == 0 && j == 0) p[i][j] = 1; else if (j == 0) p[i][j] = p[i - 1][j] * P; else { p[i][j] = p[i][j - 1] * Q; } } } for (int i = 0; i < n << 1; i++) { for (int j = 0; j < m << 1; j++) { h[i + 1][j + 1] = h[i][j + 1] + h[i + 1][j] - h[i][j] + (s[i % n][j % m]=='.') * p[i][j]; } } int tx = 0, ty = 0; for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { if (i == 0 && j == 0) continue; int l = 1, r = n, res = 0; while (l <= r) { int mid = l + r >> 1; if (equal(tx, ty, i, j, mid, m)) res = mid, l = mid + 1; else r = mid - 1; } l = 1, r = m; int res2 = 0; while (l <= r) { int mid = l + r >> 1; if (equal(tx, ty, i, j, res + 1, mid)) res2 = mid, l = mid + 1; else r = mid - 1; } if (res == n && res2 == m) continue; if (s[(i + res) % n][(j + res2) % m] < s[(tx + res) % n][(ty + res2) % m]) tx = i, ty = j; } } for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { printf("%c", s[(i + tx) % n][(j + ty) % m]); } printf("\n"); } }

__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17530278.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(12)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示