题目链接:https://www.luogu.com.cn/problem/P1220
题意:给定n个灯,最开始村长在第s个路灯处。
然后给定每个路灯的位置ai和每秒钟消耗的电量bi。(ai递增)
(1<=s<=n<=50)。
最开始关上s灯,不费时间。问从关s灯开始到关完所有灯最少花费多少时间。
题解:dp[i][j][0/1]分别表示关掉i~j之间的灯后留在i还是j(每种情况又有两种转移状态,比如i可能是由i+1或者j转移而来)。然后枚举区间即可。
另外还需要注意的是,需要+sum[i][j](前面消耗时间累积的消耗电量,至于操作,想一想也不难)。
代码:
struct XXX {
ll n,s,a[maxn],b[maxn],pre[maxn];
//pre为前缀和
ll sum[maxn][maxn],dp[maxn][maxn][2];
//sum[i][j]表示已经关掉i~j之间灯后剩余的灯每s 消耗的总电量。
//dp[i][j][0],dp[i][j][1]分别表示关掉i,j之间的灯最后停在i还是j
//每种情况又分别i+1/j->i;j-1/i->j。就是这两种情况做转移状态
void init() {
read(n),read(s);
for(ll i=1; i<=n; i++) read(a[i]),read(b[i]),pre[i]=pre[i-1]+b[i];
}
void init1() {
for(ll i=1; i<=n; i++)
for(ll j=1; j<=n; j++)
sum[i][j]=pre[n]-(pre[j]-pre[i-1]),dp[i][j][0]=dp[i][j][1]=inf;
// dp[s][s][0]=dp[s][s][1]=0;
}
ll solve() {
init1();
//枚举可能的区间
for(ll i=s; i>=1; i--) {
for(ll j=s; j<=n; j++) {
if(i==j) {
dp[i][j][0]=dp[i][j][1]=0;
continue;
}
dp[i][j][0]=min(dp[i+1][j][0]+(a[i+1]-a[i])*sum[i+1][j],
dp[i+1][j][1]+(a[j]-a[i])*sum[i+1][j]);//注意这里的*sum,是不停处理叠加的时间*每颗灯的消耗
dp[i][j][1]=min(dp[i][j-1][1]+(a[j]-a[j-1])*sum[i][j-1],
dp[i][j-1][0]+(a[j]-a[i])*sum[i][j-1]);
}
}
return min(dp[1][n][0],dp[1][n][1]);
}
void write() {
print(solve(),' ');
}
} X;
int main() {
X.init();
X.solve();
X.write();
return 0;
}