【題解】打地鼠 SDOI2011 模擬 行列無關

Prelude

爲何洛谷上的題解都是剪枝作的啊!就沒有人寫複雜度靠譜的算法嗎!
傳送到洛谷:( ̄、 ̄)
傳送到BZOJ:( ´・・)ノ(._.`)
本篇博客地址:o(><;)oophp


Solution

首先\(O(n^6)\),或者是\(O(n^4 \log^2 n)\)的模擬很是好想,枚舉錘子的長寬,而後從左上角開始挨個砸就能夠了。
枚舉的複雜度是\(O(n^2)\)的,模擬一次的複雜度是\(O(n^4)\)的,也能夠用BIT作到一次模擬\(O(n^2 \log^2 n)\)
仔細想了想發現彷佛無法合理枚舉,那就只能發掘性質了。
直覺告訴我彷佛是行列無關的。
具體來講,咱們首先固定錘子的長爲1,而後枚舉錘子的寬,求出當長爲1的時候最大可行的寬,叫作\(c\)
而後再固定錘子的寬爲1,枚舉錘子的長,求出當寬爲1的時候最大可行的長,叫作\(r\)
上面兩步能夠用\(O(n^4)\)的暴力模擬來作,或者是用BIT作到\(O(n^3 \log n)\)
那麼這個\(r\)\(c\)就是最終答案。
試着證實了一下,確實是這樣的,具體證實我沒有仔細想,大概感受是從「每一個格子被敲打的次數是行列無關的」這條入手?
而後就A掉了。
由於我比較懶,因此寫的是\(O(n^4)\)的方法,畢竟這個模擬常數小嘛,\(O(n^4)\)過100確定沒問題啦。html


Code

#include <cstring>
#include <algorithm>
#include <cstdio>

using namespace std;
const int MAXN = 110;
int _w;

int n, m, a[MAXN][MAXN], tot;
int r, c, b[MAXN][MAXN];
int t[MAXN][MAXN];

bool check( int x ) {
    for( int i = 1; i <= r; ++i )
        for( int j = 1; j <= c; ++j )
            t[i][j] = b[i][j];
    for( int i = 1; i <= r; ++i )
        for( int j = 1; j <= c-x+1; ++j )
            for( int k = j+x-1; k >= j; --k )
                t[i][k] -= t[i][j];
    for( int i = 1; i <= r; ++i )
        for( int j = 1; j <= c; ++j )
            if( t[i][j] ) return false;
    return true;
}

void solve() {
    r = n, c = m;
    for( int i = 1; i <= r; ++i )
        for( int j = 1; j <= c; ++j )
            b[i][j] = a[i][j];
    for( int x = c; x >= 1; --x )
        if( check(x) ) {
            tot /= x;
            break;
        }
    r = m, c = n;
    for( int i = 1; i <= r; ++i )
        for( int j = 1; j <= c; ++j )
            b[i][j] = a[j][i];
    for( int y = c; y >= 1; --y )
        if( check(y) ) {
            tot /= y;
            break;
        }
    printf( "%d\n", tot );
}

int main() {
    _w = scanf( "%d%d", &n, &m );
    tot = 0;
    for( int i = 1; i <= n; ++i )
        for( int j = 1; j <= m; ++j ) {
            _w = scanf( "%d", &a[i][j] );
            tot += a[i][j];
        }
    solve();
    return 0;
}
相關文章
相關標籤/搜索