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]\)
    • $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]\)

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;	
}
posted @ 2020-07-04 12:11  ♞老姚♘  阅读(196)  评论(0编辑  收藏  举报