MM不哭

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])
    • $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
",Min(dp[1][n][0],dp[1][n][1]));
}
int main(){	
	Init();
	Solve();
	return 0;	
}
原文地址:https://www.cnblogs.com/hbhszxyb/p/13234474.html