Educational Codeforces Round 59 (Rated for Div. 2) D Compression 【dp】

版权声明:如需转载,记得标识出处 https://blog.csdn.net/godleaf/article/details/86906385

题目链接: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;
}

猜你喜欢

转载自blog.csdn.net/godleaf/article/details/86906385