最近模擬賽略頻繁,導致部落格有點斷片,自己的計畫有點停滯不前,以此來督促一下自己。
題目中說兩個矩陣不可以相交,那麼這兩個矩陣肯定就可以被一條線在原來的矩陣中分開,當然可能是橫線也可能是豎線。所以我們可以列舉這條分割線,最多列舉200次,這樣列舉的前提就是我們已經求出了分割線兩邊的大矩陣中的和最大的子矩陣。
那麼就是,給出分割線i,以豎直的為例,我們要求的是(1,1)-(n,i)這個大矩陣中的和最大的子矩陣,這裡可以用dp的思想。我們設sum[i][0]表示總矩陣第i列至左端這個矩陣中最大子矩陣和,sum[i][1]表示第i列至最右端的最大和。pre[i][j][k]表示以(j,i)-(k,i)為最右邊一條邊的矩陣中和的最大值(畫一畫就很形象了,原諒我的文字描述很難看)。pre[i][j][k] = max(pre[i-1][j][k], 0) + col[i][k] - col[i][j],其中col[i][j]表示第i列的前j個之和。我們需要列舉的只有i,j,k,也就是o(n^3)。sum[i][0] = max(j <= k <= n)。類似地,我們可以求出sum[i][1]。於是有 ans = max。
類似地,在使分割線橫著求一遍sum[i][0]和sum[i][1]即可,就是sum[i][0]表示第i行以上的最大子矩陣和。
當然這還不夠,因為可能兩個和都是負數,最後相乘得到正數,這就需要我們再作一次上面的工作,僅僅把求pre陣列中的max改為min就好。
自己醜陋的**,四個過程(豎線-正,豎線-負,橫線-正,橫線-負),複製貼上了三次。
#include #include #include using namespace std;
int n, m, a[101][101];
long long pre[101][101][101], suf[101][101][101], col[101][101], sum[101][2];
long long ans = -(1<<30), zero = 0;
int main()
for(int i = 1; i <= m; i++) sum[i][0] = max(sum[i][0], sum[i-1][0]);
for(int i = m; i; i--)
for(int j = 1; j <= n; j++)
for(int k = j; k <= n; k++)
for(int i = 1; i < m; i++)
ans = max(ans,sum[i][0]*sum[i+1][1]);
// no.2
memset(suf, 0, sizeof suf);
memset(pre, 0, sizeof pre);
memset(sum, 0x3f, sizeof sum);
for(int i = 1; i <= m; i++)
for(int j = 1; j <= n; j++)
for(int k = j; k <= n; k++)
for(int i = m; i; i--)
for(int j = 1; j <= n; j++)
for(int k = j; k <= n; k++)
for(int i = 1; i <= m; i++) sum[i][0] = min(sum[i][0], sum[i-1][0]);
for(int i = 1; i < m; i++)
ans = max(ans, sum[i][0]*sum[i+1][1]);
// no.3
memset(col, 0, sizeof col);
memset(suf, 0, sizeof suf);
memset(pre, 0, sizeof pre);
memset(sum, -0x3f, sizeof sum);
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
col[i][j] = col[i][j-1]+a[i][j];
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
for(int k = j; k <= m; k++)
for(int i = n; i; i--)
for(int j = 1; j <= m; j++)
for(int k = j; k <= m; k++)
for(int i = 1; i <= n; i++) sum[i][0] = max(sum[i][0], sum[i-1][0]);
for(int i = 1; i < n; i++)
ans = max(ans, sum[i][0]*sum[i+1][1]);
// no.4
memset(suf, 0, sizeof suf);
memset(pre, 0, sizeof pre);
memset(sum, 0x3f, sizeof sum);
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
for(int k = j; k <= m; k++)
for(int i = 1; i <= n; i++) sum[i][0] = min(sum[i][0], sum[i-1][0]);
for(int i = n; i; i--)
for(int j = 1; j <= m; j++)
for(int k = j; k <= m; k++)
for(int i = 1; i < n; i++)
ans = max(ans, sum[i][0]*sum[i+1][1]);
printf("%lld", ans);
return 0;
}
tyvj 1198 矩陣連乘
題目描述 乙個矩陣由行列共個數排列而成。兩個矩陣和可以相乘當且僅當的列數等於的行數。乙個的矩陣乘以乙個的矩陣等於乙個的矩陣,運算量為 矩陣乘法滿足結合律,可以表示成或者是,兩者的運算量卻不同。例如當時,而 顯然第一種順序節省運算量。現在給出 個矩陣,並輸入個數,第個矩陣是 輸入格式 第一行n n 1...
Tyvj 1047 乘積最大
noip 2000 普及組 第三道 今年是國際數學聯盟確定的 2000 世界數學年 又恰逢我國著名數學家華羅庚先生誕辰90周年。在華羅庚先生的家鄉江蘇金壇,組織了一場別開生面的數學智力競賽的活動,你的乙個好朋友xz也有幸得以參加。活動中,主持人給所有參加活動的選手出了這樣一道題目 設有乙個長度n的數...
tyvj1466 最美妙的矩陣
背景 background candy的生日即將到來,飄飄乎居士希望找到乙個最美妙的矩陣送個candy作為禮物 描述 description 飄飄乎居士從pink處得知最美妙的矩陣滿足三個條件 首先,它的長和寬都必須和矩陣的邊界平行 也就是不可以出現斜的矩陣 第二 子矩陣橫豎都要滿足單調遞增 可以相...