【Comet OJ - Contest #8】C - 符文能量【dp】
题目大意:
题目链接:https://www.cometoj.com/contest/58/problem/C?problem_id=2760
有个物品,每个物品有两个属性,每次合并两个相邻的物品会合并成一个物品,但需花费代价。在开始前可以选择一段区间里的物品,然他们的两个属性全部乘。求合并后代价的最小值。
思路:
先考虑没有乘的操作,那么显然无论合并的顺序是怎样的,最终结果都相同。因为任意一次合并都没有拆散其它相邻的物品。
所以只需考虑乘的操作使得答案更小。那么设表示全部不使用乘的代价、第个物品一定使用乘的最小代价、前个物品使用了乘,第个物品不使用乘的最小代价。
设为本次代价,那么转移方程显然
最后取个即可。
代码:
#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\n",min(f[n-1][0],min(f[n-1][1],f[n-1][2])));
return 0;
}