MM不哭(dp (starstar ))
- 在一个数轴上,有 (n) 个 (MM) 在哭泣((5555)~一直哭)。
- (tcboy) 也在这个数轴上,并恰好看到了这一幕,由于每个 (MM) 哭都会让 (tcboy) 损失一定的 (rp),于是 (tcboy) 有必要去安慰她们(真命苦啊T.T)。
- 开始时,(tcboy) 站在 (k) 号 (MM) 的旁边。
- 现在知道第 (i) 个 (MM) 哭泣每秒钟会使 (tcboy) 降低 (w[i]) 的 (rp) (单位 (rp/s))。而 (tcboy) 的行走速度很慢,只有(1m/s) 。(tcboy) 安慰 (MM) 的方式很特别,不需要花费时间。
- 请计算 (tcboy) 安慰完所有 (MM),会消耗掉的 (rp) 的最小值。
Input
- 第一行包含一个整数 (N, 2<=N<=1000),表示 (MM) 的数量。
- 第二行包含一个整数 (V,1<=V<=N),表示开始时 (tcboy) 站在几号 (MM) 的旁边。
- 接下来的 (N) 行中,每行包含两个用空格隔开的整数 (D) 和 (W),用来描述每个 (MM),其中 (0<=D<=1000,0<=W<=1000)。(D) 表示 (MM) 在数轴上的位置(单位: (m)),(W) 表示每秒钟会使 (tcboy) 降低(W) 的 (rp)。
Output
- 输出只有一行:一个整数,即消耗 (rp) 之和的最小值。
- 结果不超过 (1,000,000,000)。
Sample Input
4
3
2 2
5 8
6 1
8 7
Sample Output
56
Hint
分析
- 类似的题我们也做了一些了,已经有了一定的套路,很容一想到区间 (dp) ,定义 (dp[i][j]) 表示区间 ([i,j])的 (MM) 已经不哭的最小 (rp) 丢失。但不能只处理区间 ([i,j]) 的,因为在处理区间时,([1,i-1]) 和 ([j,n]) 也一直在掉 (rp) 。掉(rp) 跟时间相关。所以,(dp[i][j]) 定义为处理完 ([i,j]) 时,所有 (MM) 让你掉的 (rp) .
- 处理完区间 ([i,j]) 时,你必定处于区间的两端,即要么在 (i) ,要么在 (j) 。转移的时候必须要确定你上个状态的位置,所以我们要加一维确定位置。
- (dp[i][j][0]) :处理完区间 ([i,j]) 时,此时你位于 位置 (i)。
- (dp[i][j][1]) :处理完区间 ([i,j]) 时,此时你位于 位置 (j)。
- 转移方程:
- (dp[i][j][0]=min(dp[i+1][j][0]+calc1,dp[i+1][j][1]+calc2);
- (calc1=(d[i+1]-d[i])*(sum[i]+sum[n]-sum[j]))
- 从 (i+1) 走到 (i) 走了 (t=d[i+1]-d[i]) 秒,在这期间每秒钟区间 ([1,i])和 ([j+1,n]) 掉了 (rp=sum[i]+sum[n]-sum[j]) 。
- (calc2=(d[j]-d[i])*(sum[i]+sum[n]-sum[j])))
- 从 (j) 走到 (i) 走了 (t=d[j]-d[i]) 秒,在这期间每秒钟区间 ([1,i])和 ([j+1,n]) 掉了 (rp=sum[i]+sum[n]-sum[j]) 。
- (calc1=(d[i+1]-d[i])*(sum[i]+sum[n]-sum[j]))
- $dp[i][j][1]=min(dp[i][j-1][0]+calc1, dp[i][j-1][1]+calc2 $
- (calc1=(d[j]-d[i])*(sum[i-1]+sum[n]-sum[j-1]))
- 从 (i) 走到 (j) 走了 (t=d[j]-d[i]) 秒,在这期间每秒钟区间 ([1,i-1])和 ([j,n]) 掉了 (rp=sum[i-1]+sum[n]-sum[j-1]) 。
- (calc2=(d[j]-d[j-1])*(sum[i-1]+sum[n]-sum[j-1])))
- 从 (j-1) 走到 (j) 走了 (t=d[j]-d[j-1]) 秒,在这期间每秒钟区间 ([1,i-1])和 ([j,n]) 掉了 (rp=sum[i-1]+sum[n]-sum[j-1]) 。
- (calc1=(d[j]-d[i])*(sum[i-1]+sum[n]-sum[j-1]))
- (dp[i][j][0]=min(dp[i+1][j][0]+calc1,dp[i+1][j][1]+calc2);
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#include <bits/stdc++.h>
const int maxn=1005;
struct Node{int w,x;}a[maxn];
bool cmp(const Node a,const Node b){return a.x<b.x;}
int n,s,dp[maxn][maxn][2],sum[maxn];
int Min(int a,int b){return a<b?a:b;}
int Get(int x,int y,int l,int r){
return (r-l)*(sum[n]-sum[y-1]+sum[x]);
}
void Init(){
scanf("%d%d",&n,&s);
for(int i=1;i<=n;i++)
scanf("%d%d",&a[i].x,&a[i].w);
std::sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++)
sum[i]=sum[i-1]+a[i].w;//前缀和
memset(dp,0x3f,sizeof(dp));
for(int i=1;i<=n;i++)
if(a[i].x==s){//找到初始位置
s=i;break;
}
}
void Solve(){
dp[s][s][1]=dp[s][s][0]=0;//还未计时,rp还在
for(int d=2;d<=n;d++)
for(int i=1,j;i<=s;i++){
if(i<s-d+1)continue;//i不能超出起点s d的范围
j=i+d-1;if(j>n)break;
dp[i][j][0]=Min(dp[i+1][j][0]+Get(i,j+1,a[i].x,a[i+1].x),dp[i+1][j][1]+Get(i,j+1,a[i].x,a[j].x));
dp[i][j][1]=Min(dp[i][j-1][0]+Get(i-1,j,a[i].x,a[j].x),dp[i][j-1][1]+Get(i-1,j,a[j-1].x,a[j].x));
}
printf("%d
",Min(dp[1][n][0],dp[1][n][1]));
}
int main(){
Init();
Solve();
return 0;
}