这是两道区间 的入门题。之所以写这篇题解大概还是因为很久没有写区间 了有些生疏。
石子合并
由于是圆形放置所以肯定要拉成线性,就 即可。
然后先考虑最小值。
表示合并 的最小代价。
那么根据区间
的套路不难得到
表示前缀和:
最后再 扫一遍答案即可,最大值处理类似。
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const LL Max=2e2+5;
const LL Inf=1e18;
LL N,Ans1=Inf,Ans2,Num[Max<<1],Sum[Max<<1],DP1[Max<<1][Max<<1],DP2[Max<<1][Max<<1];
int main(){
LL I,J,K;
scanf("%lld",&N);
for(I=1;I<=N;I++){
scanf("%lld",&Num[I]);Num[N+I]=Num[I];
}
for(I=1;I<=N*2;I++){
Sum[I]=Sum[I-1]+Num[I];
}
for(I=2*N;I>=1;I--){
for(J=I+1;J-I<N;J++){
DP1[I][J]=Inf;
for(K=I;K<J;K++){
DP1[I][J]=min(DP1[I][J],DP1[I][K]+DP1[K+1][J]+Sum[J]-Sum[I-1]);
DP2[I][J]=max(DP2[I][J],DP2[I][K]+DP2[K+1][J]+Sum[J]-Sum[I-1]);
}
}
}
for(I=1;I<=N;I++){
Ans1=min(Ans1,DP1[I][I+N-1]);
Ans2=max(Ans2,DP2[I][I+N-1]);
}
printf("%lld\n%lld",Ans1,Ans2);
return 0;
}
能量项链
类似处理。
表示合并
的最大值。
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const LL Max=1e3+5;
LL N,Ans,V[Max<<1],DP[Max<<1][Max<<1];
int main(){
LL I,J,K;
scanf("%lld",&N);
for(I=1;I<=N;I++){
scanf("%lld",&V[I]);V[I+N]=V[I];
}
for(I=2*N;I>=1;I--){
for(J=I+1;J-I<N;J++){
for(K=I;K<J;K++){
DP[I][J]=max(DP[I][J],DP[I][K]+DP[K+1][J]+V[I]*V[K+1]*V[J+1]);
}
}
}
for(I=1;I<=N;I++){
Ans=max(Ans,DP[I][I+N-1]);
}
printf("%lld",Ans);
return 0;
}