【Comet OJ - Contest #8】C - 符文能量【dp】

题目大意:

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


思路:

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

最后取个 m i n min min即可。


代码:

#include 
#include 
#include 
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;
}

你可能感兴趣的:(dp)