一道区间dp
先预处理出关掉了第i~j盏灯时的功率
然后f[i][j][0/1]表示关到灯i~j此时在左边(0)或右边(1)时最小的花费
有点像[HNOI2010]合唱队 这题也是三维
#include<bits/stdc++.h> using namespace std; #define Max(x,y) (x)>(y)?(x):(y) #define Min(x,y) (x)>(y)?(y):(x) #define ll long long #define rg register const int N=100+5,M=1000000+5,inf=0x3f3f3f3f,P=19650827; int n,s,sum=0,pos[N],w[N],f[N][N][2],t[N][N]; template <class t>void rd(t &x){ x=0;int w=0;char ch=0; while(!isdigit(ch)) w|=ch=='-',ch=getchar(); while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); x=w?-x:x; } int main(){ //freopen("in.txt","r",stdin); rd(n),rd(s); for(int i=1;i<=n;++i) rd(pos[i]),rd(w[i]),sum+=w[i]; for(int i=1;i<=n;++i) for(int j=i;j<=n;++j) t[i][j]=t[i][j-1]+w[j]; for(int i=1;i<=n;++i) for(int j=i;j<=n;++j) t[i][j]=sum-t[i][j]; memset(f,inf,sizeof(f)); f[s][s][0]=f[s][s][1]=0; for(int l=2;l<=n;++l)//枚举长度 for(int i=1,j;i<=n-l+1;++i){//枚举左端点 j=l+i-1; f[i][j][0]=Min(f[i+1][j][0]+t[i+1][j]*(pos[i+1]-pos[i]),f[i+1][j][1]+t[i+1][j]*(pos[j]-pos[i])); f[i][j][1]=Min(f[i][j-1][1]+t[i][j-1]*(pos[j]-pos[j-1]),f[i][j-1][0]+t[i][j-1]*(pos[j]-pos[i])); } printf("%d",Min(f[1][n][0],f[1][n][1])); return 0; }