MM不哭
MM不哭(dp \(\star\star \))
- 在一个数轴上,有 \(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\n",Min(dp[1][n][0],dp[1][n][1]));
}
int main(){
Init();
Solve();
return 0;
}
hzoi