題解 P1736 【創意吃魚法】
阿新 • • 發佈:2018-12-02
主要思路:二維DP + 二維字首和
我就講講我當時做這道題的想法就好了。如果你只拿了部分分,可以看看修改和優化方法。
一開始我沒看清題,一看,,,這不就是求最長的對角線嗎(當時我還只以為是左上右下方向的對角線),,,好求啊,,,簡單的dp就好啦
當這個點有魚時(a[i][j] == 1),最大的長度就是其左上的那個點的最大值+1,如果沒魚,就為0。
if(a[i][j] == 1)
f[i][j] = f[i - 1][j - 1] + 1;
else
f[i][j] = 0;
然後去找所有之中的最大值
但是,顯然不對。
後來我又看到了是整個正方形裡就只有一條對角線上有魚,突然想到最大正方形的字首和做法。相似的,我們用字首和算出這個正方形的和為對角線的值,不就只有對角線了?
WA了很多,下了一組資料看了看,發現左下右上的對角線也可以,我就把剛剛的操作按左右顛倒重新做了一遍。
還是不對。
為什麼?因為我們找的是之中的最大值,如果最大值那個被正方形的那個條件約束住了,就不會尋找比他次大卻符合條件的那個答案了。
如果聽不懂的話可以對比下我在最後統計答案的程式碼
正確:
go(i, 1, n, 1) go(j, 1, m, 1){ while (sum1[i][j] - sum1[i - ooo][j] - sum1[i][j - ooo] + sum1[i - ooo][j - ooo] != f[i][j]) f[i][j]--; maxx = max(maxx, f[i][j]);}
錯誤
go(i, 1, n, 1)
go(j, 1, m, 1)
if (sum1[i][j] - sum1[i - ooo][j] - sum1[i][j - ooo] + sum1[i - ooo][j - ooo] == f[i][j])
maxx = max(maxx, f[i][j]);
這樣程式碼是對的,不過那個while真的是煩,我們還得在dp完以後再去找合適的正方形,很浪費時間。
所以,我們可以在dp時就加上正方形的約束條件。
go(i, 1, n, 1) go(j, 1, m, 1) if (a[i][j] && sum1[i][j] - sum1[i - oo][j] - sum1[i][j - oo] + sum1[i - oo][j - oo] == f[i - 1][j - 1]) f[i][j] = f[i - 1][j - 1] + 1; else f[i][j] = 0;
若部分程式碼看不懂請到文末程式碼處尋找define,,,
這樣就OK了。
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>
using namespace std;
#define go(i, j, n, k) for (int i = j; i <= n; i += k)
#define fo(i, j, n, k) for (int i = j; i >= n; i -= k)
#define rep(i, x) for (int i = h[x]; i; i = e[i].nxt)
#define mn 2511
#define inf 2147483647
#define ll long long
#define ld long double
#define fi first
#define se second
#define root 1, n, 1
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
#define bson l, r, rt
//#define LOCAL
#define mod
#define Debug(...) fprintf(stderr, __VA_ARGS__)
inline int read(){
int f = 1, x = 0;char ch = getchar();
while (ch > '9' || ch < '0'){if (ch == '-')f = -f;ch = getchar();}
while (ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
return x * f;
}
//This is AC head above...
int n, m, a[mn][mn], f[mn][mn], sum1[mn][mn], sum2[mn][mn],g[mn][mn], maxx = -1;
#define ooo f[i][j]
#define ppp g[i][j]
inline void debug(){
go(i, 1, n, 1)
go(j, 1, m, 1)
printf("%d%c", f[i][j], (j == m ? '\n' : ' '));
puts("");
go(i, 1, n, 1)
go(j, 1, m, 1)
printf("%d%c", g[i][j], (j == m ? '\n' : ' '));
}
int main(){
n = read(), m = read();
go(i, 1, n, 1)
go(j, 1, m, 1)
a[i][j] = read();
go(i, 1, n, 1)
go(j, 1, m, 1)
sum1[i][j] = sum1[i - 1][j] + sum1[i][j - 1] - sum1[i - 1][j - 1] + a[i][j];
go(i, 1, n, 1)
go(j, 1, m, 1)
if (a[i][j])
f[i][j] = f[i - 1][j - 1] + 1;
else
f[i][j] = 0;
go(i, 1, n, 1)
go(j, 1, m, 1){
while (sum1[i][j] - sum1[i - ooo][j] - sum1[i][j - ooo] + sum1[i - ooo][j - ooo] != f[i][j])
f[i][j]--;
maxx = max(maxx, f[i][j]);}
//cout << maxx << "\n";
go(i, 1, n, 1)
fo(j, m, 1, 1)
sum2[i][j] = sum2[i - 1][j] + sum2[i][j + 1] - sum2[i - 1][j + 1] + a[i][j];
go(i, 1, n, 1)
fo(j, m, 1, 1)
if (a[i][j])
g[i][j] = g[i - 1][j + 1] + 1;
else
g[i][j] = 0;
go(i, 1, n, 1)
fo(j, m, 1, 1) {
while (sum2[i][j] - sum2[i - ppp][j] - sum2[i][j + ppp] + sum2[i - ppp][j + ppp] != g[i][j])
g[i][j]--;
maxx = max(maxx, g[i][j]);}
//debug();
cout << maxx;
#ifdef LOCAL
Debug("\nMy Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
return 0;
}