P9505 『MGOI』Simple Round I | D. 魔法环
DP 做法
这道题可以用 DP 做,也是一类分段问题。
我们知道这道题的元素构成了一个环,没法直接 DP,考虑以魔供值为
为什么可以这么做呢?因为将魔供值为
那么我们照上述方法将环断成链,设该链上精灵的魔供值从左往右依次为为
设
其中
不过题目中说的是至少选
不过千万别忘了赋初始值,首先,将所有
代码实现
#include<bits/stdc++.h>
using namespace std;
const int N=3010,M=105;
int p[N],q[N]; long long dp[N][M];
inline long long val(int pl,int pr){
// 不用 inline 连吸氧都卡不过
int cnt=(pr-pl-1)*(pr-pl)>>1;
return 1ll*max(p[pl],p[pr])*cnt+p[pr]*p[pr];
}
int main(){
int n,m,pos;scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&q[i]);
for(int i=1;i<=n;i++) if(!q[i]) pos=i;
for(int i=1;i<=n;i++) p[i]=q[(i+pos-1-1)%n+1];
memset(dp,127,sizeof(dp)); dp[1][1]=0;
for(int i=1;i<=n;i++){
for(int j=2;j<=min(i,m);j++){
for(int k=1;k<i;k++){
dp[i][j]=min(dp[i][j],dp[k][j-1]+val(k,i));
if(j==m) dp[i][j]=min(dp[i][j],dp[k][j]+val(k,i));
}
}
}
long long ans=LLONG_MAX;
for(int i=1;i<=n;i++) ans=min(ans,dp[i][m]+val(i,n+1));
printf("%lld",ans); return 0;
}