Comet OJ - Contest #8

前提是你 提交于 2019-11-27 01:21:49

---恢复内容开始---

     Comet OJ - Contest #8参赛总结——林荫

  1. 本人还是一如既往的菜。
  2. Comet OJ - Contest #X属于ACM赛制
  3. 六道题目难度从入门到金牌递增

  本次总结给出T3,4分析与解法(5,6以后填坑)

  T3:符文能量

  • 1000ms,256MB
  1. 题目描述

    米薇女王万万没有想到考德威尔男爵的真实意图。她的脑海里浮现出莱里亚的秀美山河,可惜再也回不去了。

    不过所幸的是,她还有着军队和重整山河的勇气。雷纳德为米薇女王呈上了 nnn 块符文石。符文石可以帮助你更好的战斗。每个符文石拥有能量,米薇可以挑选类型相近的符文石融合并释放出能量。

    形象的,我们可以把每个符文石 PiP_iPi 描述成一个二元组 (ai,bi)(a_i,b_i)(ai,bi) 。对于两个相邻的符文石 PiP_iPiPi+1 P_{i+1}Pi+1,可以把他们融合为 (ai,bi+1)(a_i,b_{i+1})(ai,bi+1) 并释放出 ai+1∗bia_{i+1}*b_iai+1bi 的能量。融合完的符文石会替换掉原本的两个二元组,出现在他们的位置上。米薇希望把所有的 nnn 个符文石融合成 111 个符文石。你可以以任意顺序合并相邻的两个符文石。

    幸运的是,米薇找到了一个法力通天的术士,在全部融合过程前你可以选择一段连续的区间将里面的符文石精炼。即把原本的一段二元组 (ai,bi)(a_i,b_i)(ai,bi) 乘 kkk 变为 (ai⋅k,bi⋅k)(a_i \cdot k,b_i \cdot k)(aik,bik)。当然你也可以不选择任何区间。注意此操作必须在初始状态进行。

    她希望她释放的能量尽可能小并想知道这个值是多少。

    你可以结合样例解释来理解题目。

     

  2. 输入描述

    111 行 222 个整数 nnn 与 kkk 。 代表有 nnn 块符文石,精炼符文石的倍率为kkk。

    接下来 nnn 行,每行 222 个整数 aia_iaibib_ibi 。描述第 iii 个符文石的属性。

    • 2≤n≤1052\leq n\leq 10^52n105
    • 0≤∣ai∣,∣bi∣,∣k∣≤2000 \leq |a_i|,|b_i|,|k|\leq 2000ai,bi,k200

    输出描述

    一个整数,释放能量的最小值

  3. 样例输入 1

    4 -1
    -1 -2
    2 3
    3 4
    -3 5
  4. 样例输出 1

    -25

  分析:提供一种和正解不沾边的做法:观察题目可知,所给入的参数a[1]和b[n]是不参与计算的。进而可得知如果不考虑精炼的话,原始式子的答案固定,即为sum(i=1,i<n)a[i+1]*b[i]下面开始考虑精炼的情况。

   手动推导式子可以得到一个神奇的发现:如果假设精炼的区间为L,R,那么答案就是a[2]*b[1]+a[3]*b[2]+a[4]*b[3]......+a[L-1]*b[L-2]+a[L]*b[L-1]*K+a[L+1]*b[L]*K^2+a[L+2]*b[L+1]*K^2.......a[R]*b[R-1]*K^2+a[R+1]*b[R]*K+a[R+2]*b[R+1].......

  然后这个问题就变成了求上述式子的最小值。

  那果断DP啊。

  至于方程?状态:DP[i][0]在1——i的区间内不使用精炼的最小值,DP[i][1]在1——i的区间内已经开始精炼,但是精炼未结束的最小值。DP[i][2]在1——i的区间内已经完成精炼的最小值

  

for(int i=1;i<n;i++)
    {
        dp[i][0]=dp[i-1][0]+sum[i];
        dp[i][1]=min(dp[i-1][0]+sum[i]*k,dp[i-1][1]+sum[i]*k*k);
        dp[i][2]=min(dp[i-1][1]+sum[i]*k,dp[i-1][2]+sum[i]);
    }

  标程放上!

#include<iostream>
#include<cstdio>
using namespace std;
long long int n,k,a1,a2;
long long int sum[100001];
long long int dp[100001][3];
int main()
{
    scanf("%lld%lld",&n,&k);
    scanf("%lld",&a1);
    for(int i=1;i<n;i++)
    {
        scanf("%lld%lld",&a1,&a2);
        sum[i]=a1*a2;
    }
    scanf("%lld",&a1);
    for(int i=1;i<n;i++)
    {
        dp[i][0]=dp[i-1][0]+sum[i];
        dp[i][1]=min(dp[i-1][0]+sum[i]*k,dp[i-1][1]+sum[i]*k*k);
        dp[i][2]=min(dp[i-1][1]+sum[i]*k,dp[i-1][2]+sum[i]);
    }
    cout<<min(dp[n-1][0],min(dp[n-1][2],dp[n-1][1]));
    return 0;
}

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!