男神的礼物
Time Limit: 3000/3000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others)
Submit Status
Lweb学长是集训队里公认的男神。有一天他要给美美的学姐姐准备礼物。
Lweb学长可是会魔法的哟。为了准备一份礼物,男神要加工n份材料。每一次只能加工相邻的材料。
当男神加工两个魔法值为a,b的材料,男神都要消耗a*b的体力,同时在这个地方合成出魔法值(a+b)%100的材料。
男神为了能节省体力来完成他的礼物。想找聪明的你帮他算一算他所要花费的最小体力。
Input
第一行一个整数T,表示男神所要准备的礼物数。 之后的T组数据各有两行数据,第一行有一个整数n,表示这份礼物的材料数(1<=n<=100)。 接下来一行有n个整数a(0<=a<100),表示这件礼物第i份材料的魔法值。
Output
每组数据一行输出,表示男神制作这份礼物所要的最小体力。
Sample input and output
Sample Input | Sample Output |
---|---|
2
2
18 19
3
40 60 20 | 342
2400 |
Hint
对于样例 2:
先加工材料40和60,得到0的材料,消耗40∗∗60体力,共消耗2400体力;
再加工材料0和20,得到20的材料,消耗0∗∗20体力,共消耗2400体力.
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <map>
#include <vector>
#include <queue>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define MM(a,b) memset(a,b,sizeof(a));
#define inf 0x7f7f7f7f
#define FOR(i,n) for(int i=1;i<=n;i++)
#define CT continue;
#define PF printf
#define SC scanf
const int mod=1000000007;
const int N=1e3+10;
int dp[105][105],sum[105];
int main()
{
int cas,n,x;
scanf("%d",&cas);
while(cas--)
{
MM(dp,inf);MM(sum,0);
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&x);
dp[i][i]=0;
sum[i]=sum[i-1]+x;
}
for(int r=2;r<=n;r++)
for(int l=r-1;l>=1;l--)
for(int k=l;k<=r-1;k++)
{
int ener=((sum[k]-sum[l-1])%100)*((sum[r]-sum[k])%100);
dp[l][r]=min(dp[l][r],dp[l][k]+dp[k+1][r]+ener);
}
printf("%d\n",dp[1][n]);
}
return 0;
}
分析:设dp[l][r]为合并区间[l,r]范围材料的体力消耗,先固定l,r然后枚举中间值k(k代表将[l,k]和
[k+1,r]范围内的材料合并,当然前提是两边的数合并的结果已经算出来了),
dp[l][r]=min(dp[l][k]+dp[k+1][r]+消耗); 复杂度n^3;