• 【Comet OJ


    题目大意:

    题目链接:https://www.cometoj.com/contest/58/problem/C?problem_id=2760
    nn个物品,每个物品有a,ba,b两个属性,每次合并两个相邻的物品i,i+1i,i+1会合并成一个(ai,bi+1)(a_i,b_{i+1})物品,但需花费代价ai+1×bia_{i+1} imes b_i。在开始前可以选择一段区间里的物品,然他们的两个属性全部乘kk。求合并后代价的最小值。


    思路:

    先考虑没有乘kk的操作,那么显然无论合并的顺序是怎样的,最终结果都相同。因为任意一次合并都没有拆散其它相邻的物品。
    所以只需考虑乘kk的操作使得答案更小。那么设f[i][0/1/2]f[i][0/1/2]表示全部不使用乘kk的代价、第ii个物品一定使用乘kk的最小代价、前i1i-1个物品使用了乘kk,第ii个物品不使用乘kk的最小代价。
    c[i]c[i]为本次代价,那么转移方程显然
    f[i][0]=f[i1][0]+c[i]f[i][0]=f[i-1][0]+c[i]
    f[i][1]=min(f[i1][0]+c[i]×k,f[i1][1]+c[i]×k×k)f[i][1]=min(f[i-1][0]+c[i] imes k,f[i-1][1]+c[i] imes k imes k)
    f[i][2]=min(f[i1][2]+c[i],f[i1][1]+c[i]×k)f[i][2]=min(f[i-1][2]+c[i],f[i-1][1]+c[i] imes k)

    最后取个minmin即可。


    代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    
    const int N=100010;
    int n;
    ll f[N][3],a[N],b[N],c[N],k;
    
    int main()
    {
    	scanf("%d",&n);
    	scanf("%lld",&k);
    	for (int i=1;i<=n;i++)
    	{
    		scanf("%lld%lld",&a[i],&b[i]);
    		if (i>=2) c[i-1]=a[i]*b[i-1];
    	}
    	memset(f,0x3f3f3f3f,sizeof(f));
    	f[0][0]=f[0][1]=f[0][2]=0;
    	for (int i=1;i<n;i++)
    	{
    		f[i][0]=f[i-1][0]+c[i];
    		f[i][1]=min(f[i-1][0]+c[i]*k,f[i-1][1]+c[i]*k*k);
    		f[i][2]=min(f[i-1][2]+c[i],f[i-1][1]+c[i]*k);
    	}
    	printf("%lld
    ",min(f[n-1][0],min(f[n-1][1],f[n-1][2])));
    	return 0;
    }
    
  • 相关阅读:
    函数练习之计算机
    函数练习小程序
    Java—Day5课堂练习
    mysql-用户权限管理
    liunx-tail 实时显示文件内容
    Linux-diff --比较两个文件并输出不同之处
    linux-查找某目录下包含关键字内容的文件
    mysql-允许远程连接
    mysql-基本操作
    liunx-指令
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998064.html
Copyright © 2020-2023  润新知