题意:有n个路灯,每个路灯打开有自己的花费ai,现在由你来决定每个灯的开关,使得最终的总花费最小;路灯的要求是:相邻的两个路灯至少有一个亮着;还有一条规则是,可以有k次机会交换两个路灯,求最终最小的花费;
分析:如果不加可以交换k次这个条件,就是一个简单一点的DP;这里我们令dp[i][j][k][l]表示前i个路灯中,提前给后面用了j个,提前借走了后面的k个,并且当前的前两个位置路灯的状态为l时的最小花费;
#include<bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
const int maxn=250007;
const int mod=1e9+7;
const ll INF=1e18;
ll dp[maxn][10][10][3];
ll a[maxn];
int main()
{
int n,m;scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%lld",&a[i]);
memset(dp,0x3f,sizeof(dp));
dp[0][0][0][0]=0;
for (int i=1;i<=n;i++)
for (int j=0;j<=m;j++)
for (int k=0;k<=m;k++)
{
dp[i][j][k][0]=dp[i-1][j][k][2];
if(k) dp[i][j][k][0]=min(dp[i][j][k][0],dp[i-1][j][k-1][2]+a[i]);
dp[i][j][k][1]=dp[i-1][j][k][0];
if(k) dp[i][j][k][1]=min(dp[i][j][k][1],dp[i-1][j][k-1][0]+a[i]);
dp[i][j][k][2]=min(dp[i][j][k][2],dp[i-1][j][k][0]+a[i]);
dp[i][j][k][2]=min(dp[i][j][k][2],dp[i-1][j][k][1]+a[i]);
dp[i][j][k][2]=min(dp[i][j][k][2],dp[i-1][j][k][2]+a[i]);
if(j)
{
dp[i][j][k][2]=min(dp[i][j][k][2],dp[i-1][j-1][k][0]);
dp[i][j][k][2]=min(dp[i][j][k][2],dp[i-1][j-1][k][1]);
dp[i][j][k][2]=min(dp[i][j][k][2],dp[i-1][j-1][k][2]);
}
}
ll ans=INF;
for (int i=0;i<=m;i++)
for (int j=0;j<=2;j++) if(j!=1) ans=min(ans,dp[n][i][i][j]);
printf("%lld\n",ans);
return 0;
}