为何洛谷上的题解都是剪枝作的啊!就没有人写复杂度靠谱的算法吗!
传送到洛谷:( ̄、 ̄)
传送到BZOJ:( ´・・)ノ(._.`)
本篇博客地址:o(><;)oophp
首先\(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
#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; }