• 刷题总结——array(ssoj)


    题目:

    题目描述

    给定 2 个正整数序列 A1, A2,序列长度分别为 L1, L2。
    你可以进行以下的一次操作:
    1. 选择两个数 K1,K2(1≤K1≤L1, 1≤K2≤L2);
    2. 移去 A1 中最后 K1 个数,得到这 K1 个数的和 S1,L1 对应减少 K1;
    3. 移去 A2 中最后 K2 个数,得到这 K2 个数的和 S2,L2 对应减少 K2;
    此次操作的费用为:(S1-K1) * (S2-K2)。
    进行以上操作直至两个序列都为空,求最小的费用总和。
    注意:序列为空当且仅当两个序列同时为空。

    输入格式

    第一行是两个正整数 L1和 L2,表示 A1 与 A2 的长度。
    第二行 L1 个整数,表示序列 A1[1..L1]。
    第三行 L2 个整数,表示序列 A2[1..L2]。

    输出格式

    输出一个整数,表示最小费用。

    样例数据 1

    输入  [复制]

     
    3 2 
    1 2 3 
    1 2

    输出

    2

    备注

    【样例说明】
    第一次选取 K1=1,K2=1。费用为 (3-1)*(2-1) = 2。
    第二次选取 K1=2,K2=1。费用为 (1+2-2)*(1-1) = 0。
    所以,总费用为 2。

    【数据范围】
    对 20% 的输入数据:1≤L1,L2≤20
    对 40% 的输入数据:1≤L1≤400;1≤L2≤150
    对 100% 的输入数据:1≤L1,L2,A1[1..L1],A2[1..L2]≤5,000

    题解:

    很好的一道dp题·····

    首先容易想到,为了消除每次sum-k中k带来的影响,我们可以将所有元素-1,这样每次计算的时候直接sum相乘即可····

    然后考虑消除的策略···

    打个比方l1=l2=4···我们如果要消除a1[l1]到a1[2]和a2[l2]到a2[3]这两段区间的数的话···最好的策略肯定不是直接一次性消除···而是先消除a1[l1]和a2[l2]这两个数,再消除a1[3]到a1[2]和a2[3]这两段····因此不难发现··每次消除的话a1和a2的区间长度有一个一定为1!

    所以我们可以将区间消除转化为要么消除两段末端a1[x],a2[y]中其中一个··要么同时消除两个末端··且此时对答案的贡献为a1[x]*a2[y];

    得出dp方程

    f[i][j]=min(f[i][j+1],f[i+1][j],f[i+1][j+1])+a1[i+1]*a2[j+1]

    其中f[i][j]表示两段分别剩余i,j个数时的最少费用

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<ctime>
    #include<cctype>
    #include<cstring>
    #include<string>
    #include<algorithm>
    using namespace std;
    const int N=5001;
    const int inf=0x3f3f3f3f;
    inline int R()
    {
      char c;int f=0,i=1;
      for(c=getchar();(c<'0'||c>'9')&&c!='-';c=getchar());
      if(c=='-')  c=getchar(),i=-1;
      for(;c<='9'&&c>='0';c=getchar())  f=(f<<3)+(f<<1)+c-'0';
      return f*i;
    }
    int l1,l2,a1[N],a2[N];
    int f[N][N];
    int main()
    {
      //freopen("a.in","r",stdin);
      l1=R(),l2=R();
      memset(f,inf,sizeof(f));
      for(int i=1;i<=l1;i++)  a1[i]=R(),a1[i]--;
      for(int i=1;i<=l2;i++)  a2[i]=R(),a2[i]--;
      f[l1-1][l2-1]=a1[l1]*a2[l2];
      for(int i=l1-1;i>=0;i--)
        for(int j=l2-1;j>=0;j--)  
        {  
          if(i==l1-1&&j==l2-1)  continue;
          f[i][j]=min(f[i][j+1],min(f[i+1][j+1],f[i+1][j]))+a1[i+1]*a2[j+1];
        }
      cout<<f[0][0]<<endl;
      return 0;
    }
  • 相关阅读:
    software architect
    bmh算法
    程序动态切片技术研究
    chm便捷制作
    protobuffer源码解读
    字符串搜索算法比较
    软件架构重组:实践需要和当前做法
    游戏素材制作
    ea(enterprise architect) 相关资料集锦
    vs开启工程非常卡分析和解决
  • 原文地址:https://www.cnblogs.com/AseanA/p/7638304.html
Copyright © 2020-2023  润新知