题目链接:http://codeforces.com/contest/1107/problem/D
这道题只要把主要问题找出来就有思路了。
题目的矩阵是 n*n的,要想压缩成 n/x *n/x 的矩阵需要满足一个条件,假设x == 2,那么这个矩阵将会被分成4小块矩阵,如果这四个小矩阵每一块要么全是1要么全是0,那这个矩阵就能压缩成n/2 *n/2的矩阵。
因为题目给的n比较大,如果暴力求小矩阵是否全是1或者0肯定会超时的。
我用的方法是dp求出每一个 左上角为0*0,右下角为i*j 这个矩阵的和,当我们需要某一块小矩阵的时候,能直接取出dp[i][j] 并且除去不需要的部分就能很快的知道某个小矩阵的和。
只要主要问题能找出来,上面的dp应该也能想得到,其次还有一个难点就是输入的快慢。
起初的方法是用一个字符串存16个二进制数,然后一个一个的放入矩阵里面,但是这种方法非常慢。
换成二进制位移判断1或0的方法赋值能快非常多。
#include <iostream>
#include <queue>
#include <cstring>
#include <string>
#include <map>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
const int Maxn = 6e3+10;
int dp[Maxn][Maxn], n;
char G[Maxn][Maxn];
void init() {
for(int i = 0; i < n; ++i)
if(G[i][0] == '1') dp[i][0] = 1;
for(int i = 0; i < n; ++i) {
for(int j = 1; j < n; ++j) {
dp[i][j] += dp[i][j-1];
if(G[i][j] == '1') dp[i][j]++;
}
}
for(int j = 0; j < n; ++j) {
for(int i = 1; i < n; ++i) {
dp[i][j] += dp[i-1][j];
}
}
}
void solve() {
int ans = 1;
for(int i = 2; i <= n; ++i) {
bool ok = true;
if(n % i != 0) continue;
for(int ii = i-1; ii <= n; ii += i) {
for(int jj = i-1; jj <= n; jj += i) {
int tmp = dp[ii][jj];
if(ii-i >= 0 && jj-i >= 0) tmp += dp[ii-i][jj-i];
if(ii-i >= 0) tmp -= dp[ii-i][jj];
if(jj-i >= 0) tmp -= dp[ii][jj-i];
if(tmp == 0 || tmp == i*i) continue;
else {
ok = false; break;
}
}
if(!ok) break;
}
if(ok) ans = i;
}
printf("%d\n", ans);
}
int main(void)
{
char str[Maxn];
scanf("%d", &n);
for(int i = 0; i < n; ++i) {
scanf("%s", str);
for(int j = 0; j < (n>>2); ++j) {
int num = str[j] <= '9' ? str[j]-'0' : str[j]-'A'+10;
int fir = j*4;
for(int k = 0; k < 4; ++k) {
if((num>>k) & 1) G[i][fir+3-k] = '1';
else G[i][fir+3-k] = '0';
}
G[i][fir+4] = '\0';
}
}
memset(dp, 0, sizeof(dp));
init();
solve();
return 0;
}