26 · 内积

26 · 内积
 

给定长度为NNN的AAA数组,长度为KKK的BBB数组
你可以从AAA数组里取KKK个数
规则如下:

    每个AiA_iA​i​​只能被取出一次
    i==1ori==Ni==1 \quad or \quad i==Ni==1ori==N 可以直接取出AiA_i\quadA​i​​
    2≤i≤N−12 \leq i \leq N-1\quad2≤i≤N−1 若Ai−1A_{i-1}A​i−1​​ 或者 Ai+1A_{i+1}A​i+1​​ 已经取出,则可以取出AiA_iA​i​​
    要取出正好KKK个数

即每次可以从AAA数组的最左边或者最右边取走一个数,取走的数从数组中移除
将取出的AiA_iA​i​​按取出的顺序 组成CCC数组
求BBB与CCC的内积最大值

BBB与CCC内积为∑i=0K−1Bi×Ci\sum_{i=0}^{K-1}B_i \times C_i∑​i=0​K−1​​B​i​​×C​i​​

    解释1:
    AAA= [1,4,3,2,5]
    BBB=[1,2,3,4]
    KKK=4
    取出A0A_0A​0​​ ,CCC=[1]
    取出A4A_4A​4​​ CCC=[1,5]
    取出A1A_1A​1​​ CCC=[1,5,4]
    取出A2A_2A​2​​ CCC=[1,5,4,3]
    BBB·CCC=1*1+2*5+3*4+4*3=35
    这只是CCC的一种可行方案,可能不是最优方案

    解释2
    AAA=[1,2,3,4]
    不能直接取出A1A_1A​1​​ 因为A0A_0A​0​​和A2A_2A​2​​都没有取出

1≤K≤N≤20001 \leq K \leq N \leq 20001≤K≤N≤2000
1≤Ai,Bi≤1000001 \leq A_i,B_i \leq 1000001≤A​i​​,B​i​​≤100000
样例

    [2,3,5,1]
    [2,1]
    取出A0,A1A_0,A_1A​0​​,A​1​​

long long getMaxInnerProduct(vector<int> &A, vector<int> &B)

{

 

int sizeA = A.size();

    int sizeB = B.size();

    int64_t max = -1;

 

    vector<int64_t> preLeftVec(sizeA, 0);

    vector<int64_t > preRightVec(sizeA, 0);

    vector<int64_t  > curLeftVec(sizeA, 0);

    vector<int64_t  > curRightVec(sizeA, 0);

    vector<int64_t  > emptyVec(sizeA, 0);


 

    for (int i = 0; i < sizeB; i++)

    {

        //列从左边到右边

        for (int j = 0; j <= i; j++)

        {

            if (0 == j && 0 == i) //第一列

            {

                curLeftVec[j] = (int64_t)B[i] * (int64_t)A[j];

            }

            else

            {

                int64_t right = (sizeA-1) - (i - j -1) ;

                int64_t max = -1;

                int64_t leftMax = -1;

                int64_t rightMax = -1;

                if (j - 1 >= 0)

                {

                    leftMax = preLeftVec[j - 1];

                }

                if (right < sizeA)

                {

                    rightMax = preRightVec[right];

                }

                max = leftMax > rightMax ? leftMax : rightMax;

                curLeftVec[j] = (int64_t)B[i] * (int64_t)A[j] + max;

            }

            if (curLeftVec[j] > max)

            {

                max = curLeftVec[j];

            }

        }

        

        //列从右边到左边

        for (int j = sizeA - 1; j >= sizeA - 1 - i; j--)

        {

            if (sizeA - 1 == j && 0 == i)

            {

                curRightVec[j] = (int64_t)B[i] * (int64_t)A[j]; 

            }

            else

            {

                int64_t left = i -1 - ((sizeA - 1) - j);

                int64_t max = -1;

                int64_t leftMax = -1;

                int64_t rightMax = -1;

                if (left >=0 )

                {

                    leftMax = preLeftVec[left];

                }

                if (j + 1 < sizeA)

                {

                    rightMax = preRightVec[j + 1];

                }

                max = leftMax > rightMax ? leftMax : rightMax;

                curRightVec[j] = (int64_t)B[i] * (int64_t)A[j] + max;

            }

            if (curRightVec[j] > max)

            {

                max = curRightVec[j];

            }

        }

 

        preLeftVec = curLeftVec;

        preRightVec = curRightVec;

        curLeftVec = emptyVec;

        curRightVec = emptyVec;

    }

 

    return max;

}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值