# Dynamic Programming# Greedy# Array# Kadane's Algorithm

i429 - 4. 內積 (時限放寬版,給 Python 使用者)

🔗 前往 ZeroJudge 原題

題目描述

題目要求在兩個陣列 A 和 B 中分別找到一個長度相同的子區間,使得這兩個子區間的內積最大化。可以對 A 和 B 進行翻轉。

解題思路

程式碼的核心思想是枚舉所有可能的子區間長度,並計算所有可能的子區間組合的內積。為了找到最大內積,程式碼使用了類似 Kadane's Algorithm 的方法,在遍歷子區間時,維護一個當前和,並在當前和變為負數時重置為 0。程式碼還考慮了翻轉陣列 A 的情況,以找到最佳的子區間組合。

具體來說,程式碼首先計算原始陣列 A 和 B 的內積矩陣 dp[i][j] = a[i] * b[j]。然後,它遍歷所有可能的起始位置 ij,計算長度為 r 的子區間的內積,並使用 Kadane's Algorithm 找到最大內積。最後,程式碼翻轉陣列 A,並重複相同的過程,以確保找到全局最大內積。

複雜度分析

  • 時間複雜度: O(nmmin(n,m))。外層迴圈遍歷所有可能的起始位置,內層迴圈計算子區間的內積。
  • 空間複雜度: O(nm)。程式碼使用了一個大小為 nm 的二維陣列 dp 來儲存內積。

程式碼

#include <iostream>
using namespace std;
long n,m,a[1005],b[1005],dp[1005][1005],ans=-1e9;
int main(){
        cin.tie(0); ios::sync_with_stdio(0);
        cin >> n >> m;
        for(int i=0;i<n;++i)
            cin >> a[i]; 
        for(int i=0;i<m;++i)
            cin >> b[i];
        for(int i=0;i<n;++i)
            for(int j=0;j<m;++j)
                dp[i][j]=a[i]*b[j];
        for(int i=0;i<n;++i){
            long tmp=0;
            for(int j=0;i+j<n&&j<m;++j){
                tmp+=dp[i+j][j];
                ans=max(ans,tmp);
                if(tmp<0)tmp=0;
            }
        }
        for(int j=0;j<m;++j){
            long tmp=0;
            for(int i=0;i<n&&i+j<m;++i){
                tmp+=dp[i][i+j];
                ans=max(ans,tmp);
                if(tmp<0)tmp=0;
            }    
        }
        for(int i=0;i<n;++i)
            for(int j=0;j<m;++j)
                dp[i][j]=a[n-i-1]*b[j];
        for(int i=0;i<n;++i){
            long tmp=0;
            for(int j=0;i+j<n&&j<m;++j){
                tmp+=dp[i+j][j];
                ans=max(ans,tmp);
                if(tmp<0)tmp=0;
            }
        }
        for(int j=0;j<m;++j){
            long tmp=0;
            for(int i=0;i<n&&i+j<m;++i){
                tmp+=dp[i][i+j];
                ans=max(ans,tmp);
                if(tmp<0)tmp=0;
            }    
        }
        cout << ans;
}

Discussion