原文链接
。。。这一题,,,花时间最多的是看题目。
题意(别处复制):
一个长度为n的数列,将其分成若干段(每一段的长度要<=20),
要求∑ai*(2^bi)最小,其中ai是每一段数列的第一项,bi是每一段的长度。
比如sample imput
n=7,A={1 2 4 4 5 4 3},将其分成1 2 4| 4 5| 4| 3,
则其所用空间为1*2^3+4*2^2+4*2^1+3*2^1=38,
而如果分成1 2| 4 4 5| 4 3,则其所用空间为1*2^2+4*2^3+4*2^2=52,比38大。
很明显区间dp。(区间dp一般思路)
代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
long long int dp[65][65];
long long int a[65];
long long int pow2[21];
long long int sum[65];
void init()
{
pow2[0]=1;
for(long long int i=1;i<=20;i++)
pow2[i]=pow2[i-1]*2;
}
int main()
{
long long int t,n;
init();
scanf("%I64d",&t);
while(t--)
{
scanf("%I64d",&n);
sum[0]=0;
for(long long int i=0;i<n;i++)
{
scanf("%I64d",&a[i]);
if(i>0)
sum[i]=sum[i-1]+a[i];
else
sum[i]=a[i];
}
for(long long int p=1;p<=n;p++)
{
for(long long int i=0;i<n;i++)
{
long long int j=i+p-1;
if(j>=n)
break;
if(p<=20)
dp[i][j]=a[i]*pow2[j-i+1];
else
{
if(i>0)
dp[i][j]=(sum[j]-sum[i-1])*2;
else
dp[i][j]=(sum[j])*2;
}
for(long long int k=i;k<j;k++)
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]);
}
}
//for(long long int i=0;i<=n-1;i++)
//cout<<dp[0][i]<<endl;
cout<<dp[0][n-1]<<endl;
}
return 0;
}