题目链接:http://noip.ybtoj.com.cn/contest/52/problem/1
分析
区间DP经典题,枚举区间长度,端点,就可以得到另一个端点,然后枚举区间分割点,就可以转移。
所有大区间的答案都依赖于小区间,要先枚举长度。
这个环怎么处理?倍长之后正常做。
转移:
f
[
l
]
[
r
]
=
m
a
x
/
m
i
n
(
f
[
l
]
[
r
]
,
f
[
l
]
[
k
]
+
f
[
k
+
1
]
[
r
]
)
f[l][r]=max/min(f[l][r],f[l][k]+f[k+1][r])
f[l][r]=max/min(f[l][r],f[l][k]+f[k+1][r])
f
[
l
]
[
r
]
+
=
s
[
r
]
−
s
[
l
−
1
]
f[l][r]+=s[r]-s[l-1]
f[l][r]+=s[r]−s[l−1]
上代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int n,a[301],f[301][301],s[301];
int mx=0,mn=2147483600;
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
a[i+n]=a[i];
}
for(int i=1;i<=n;i++)
{
s[i]=s[i-1]+a[i];
}
for(int i=n+1;i<=2*n;i++)
{
s[i]=s[i-1]+a[i-n];
}
for(int i=1;i<=2*n;i++)
{
for(int j=1;j<=2*n;j++)
{
if(i==j) f[i][j]=0;
else f[i][j]=0x3f3f3f3f;
}
}
for(int len=2;len<=n;len++)
{
for(int l=1;l<=n*2-len+1;l++)
{
int r=l+len-1;
for(int k=l;k<=r-1;k++)
{
f[l][r]=min(f[l][r],f[l][k]+f[k+1][r]);
}
f[l][r]+=s[r]-s[l-1];
}
}
for(int i=1;i<=n;i++)
{
mn=min(mn,f[i][i+n-1]);
}
cout<<mn<<endl;
memset(f,0,sizeof(f));
for(int len=2;len<=n;len++)
{
for(int l=1;l<=n*2-len+1;l++)
{
int r=l+len-1;
for(int k=l;k<=r-1;k++)
{
f[l][r]=max(f[l][r],f[l][k]+f[k+1][r]);
}
f[l][r]+=s[r]-s[l-1];
}
}
for(int i=1;i<=n;i++)
{
mx=max(mx,f[i][i+n-1]);
}
cout<<mx;
return 0;
}