【题解】洛谷 P7170 [COCI2020-2021#3] Sateliti
题解
可以进行行循环移位和列循环移位,因此只需确定左上角的格子是原来的哪个格子,即可确定对应图形。很自然想到将原矩阵复制成左上、右上、左下、右下四份,以方便求解答案。
二维 Hash 可以判断两个子矩阵相不相等,外层套个二分确定第一个不相同的位置,就可以比较字典序大小,总时间复杂度
代码
PS:二维 Hash 可以将
笔者代码
#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
const int inv2=5e8+4;
inline int get_sum(int a,int b)
{
return a+b-(a+b>=mod?mod:0);
}
inline int get_power(int a,int n)
{
int res=1;
while(n>0)
{
res=n&1?1ll*res*a%mod:res;
a=1ll*a*a%mod;
n>>=1;
}
return res;
}
int n,m;
inline int id(int x,int y)
{
return (x-1)*(m<<1)+(y-1);
}
const int max_n=1e3+5;
const int max_m=1e3+5;
char str[max_m];
int Map[max_n<<1][max_m<<1];
const int max_tot=4e6+5;
int pow2[max_tot],pow_inv2[max_tot],Hash[max_n<<1][max_m<<1];
inline int get_Hash(int a,int b,int c,int d) // calculate the hash value of the matrix that the upper left corner is (a,b) and the lower right corner is (c,d)
{
return (1ll*Hash[c][d]-Hash[a-1][d]-Hash[c][b-1]+Hash[a-1][b-1]+2*mod)*pow_inv2[id(a,b)]%mod;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)
{
scanf("%s",str+1);
for(int j=1;j<=m;++j)
Map[i][j]=Map[i+n][j]=Map[i][j+m]=Map[i+n][j+m]=(str[j]=='.');
}
pow2[0]=1;
for(int i=1;i<=(n*m<<2);++i)
pow2[i]=get_sum(pow2[i-1],pow2[i-1]);
pow_inv2[n*m<<2]=get_power(pow2[n*m<<2],mod-2);
for(int i=(n*m<<2)-1;i>=0;--i)
pow_inv2[i]=get_sum(pow_inv2[i+1],pow_inv2[i+1]);
for(int i=1;i<=(n<<1);++i)
for(int j=1;j<=(m<<1);++j)
Hash[i][j]=(1ll*Map[i][j]*pow2[id(i,j)]+Hash[i-1][j]+Hash[i][j-1]-Hash[i-1][j-1]+mod)%mod;
int ans_x=1,ans_y=1;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
{
int L=1,R=n,res_x=n+1,res_y=m+1;
while(L<=R)
{
int mid=(L+R)>>1;
if(get_Hash(i,j,i+mid-1,j+m-1)!=get_Hash(ans_x,ans_y,ans_x+mid-1,ans_y+m-1))
res_x=mid,R=mid-1;
else
L=mid+1;
}
if(res_x==n+1)
continue;
L=1,R=m;
while(L<=R)
{
int mid=(L+R)>>1;
if(get_Hash(i+res_x-1,j,i+res_x-1,j+mid-1)!=get_Hash(ans_x+res_x-1,ans_y,ans_x+res_x-1,ans_y+mid-1))
res_y=mid,R=mid-1;
else
L=mid+1;
}
if(!Map[i+res_x-1][j+res_y-1])
ans_x=i,ans_y=j;
}
for(int i=1;i<=n;++i)
{
for(int j=1;j<=m;++j)
putchar(Map[ans_x+i-1][ans_y+j-1]?'.':'*');
putchar('\n');
}
return 0;
}
官方 std
#include <bits/stdc++.h>
using namespace std;
#define TRACE(x) cerr << #x << " = " << x << endl
#define _ << " _ " <<
#define fi first
#define se second
typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;
typedef vector<int> vi;
const int MAXN = 1010, MOD = 1e9 + 7, P = 2, Q = 3;
int pq_pow[2 * MAXN][2 * MAXN];
int h[2 * MAXN][2 * MAXN];
int add(int a, int b) {
int res = a + b;
if (res >= MOD) res -= MOD;
return res;
}
int sub(int a, int b) { return add(a, MOD - b); }
int mul(int a, int b) { return (ll)a * b % MOD; }
void precalc(const vector<string>& a) {
for (int i = 0; i < 2 * MAXN; i++) {
for (int j = 0; j < 2 * MAXN; j++) {
if (i == 0 && j == 0) pq_pow[i][j] = 1;
else if (i == 0) pq_pow[i][j] = mul(pq_pow[i][j - 1], Q);
else pq_pow[i][j] = mul(pq_pow[i - 1][j], P);
}
}
int n = a.size(), m = a[0].size();
for (int i = 0; i < 2 * n; i++) {
for (int j = 0; j < 2 * m; j++) {
int val = mul(a[i % n][j % m] == '.', pq_pow[i][j]);
h[i + 1][j + 1] = sub(add(val,
add(h[i + 1][j], h[i][j + 1])),
h[i][j]);
}
}
}
int get_h(int x, int y, int dx, int dy) {
return sub(add(h[x + dx][y + dy], h[x][y]),
add(h[x][y + dy], h[x + dx][y]));
}
bool is_equal(int x1, int y1, int x2, int y2, int dx, int dy) {
int val1 = mul(get_h(x1, y1, dx, dy), pq_pow[x2][y2]);
int val2 = mul(get_h(x2, y2, dx, dy), pq_pow[x1][y1]);
return val1 == val2;
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n, m;
cin >> n >> m;
vector<string> a(n);
for (int i = 0; i < n; i++) cin >> a[i];
precalc(a);
int sol_x = 0, sol_y = 0;
for (int x = 0; x < n; x++) {
for (int y = 0; y < m; y++) {
int lo_dx = 0, hi_dx = n;
while (lo_dx + 1 < hi_dx) {
int dx = (lo_dx + hi_dx) / 2;
if (is_equal(sol_x, sol_y, x, y, dx, m)) lo_dx = dx;
else hi_dx = dx;
}
int dx = lo_dx;
int lo_dy = 0, hi_dy = m;
while (lo_dy + 1 < hi_dy) {
int dy = (lo_dy + hi_dy) / 2;
if (is_equal(sol_x + dx, sol_y, x + dx, y, 1, dy)) lo_dy = dy;
else hi_dy = dy;
}
int dy = lo_dy;
if (a[(x + dx) % n][(y + dy) % m] <
a[(sol_x + dx) % n][(sol_y + dy) % m]) {
sol_x = x;
sol_y = y;
}
}
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++)
cout << a[(sol_x + i) % n][(sol_y + j) % m];
cout << '\n';
}
return 0;
}