zoukankan      html  css  js  c++  java
  • 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;	
    }
    
  • 相关阅读:
    2019.9.21 Tomcat基于端口的虚拟主机
    shell脚本作业
    DNS原理及其解析过程
    用户管理系统脚本
    pxe批量装机
    磁盘分区挂载脚本
    安装apache脚本
    linux远程拷贝命令及not a regular file 解决方案
    卸载虚拟网卡的方法
    watch的用法
  • 原文地址:https://www.cnblogs.com/hbhszxyb/p/13234474.html
Copyright © 2011-2022 走看看