[ACM Day1]BAPC2014 D.Lift Problem

3 篇文章 0 订阅

题目描述

On the ground floor (floor zero) of a large university building a number of students are wait- ing for a lift. Normally, the lift stops at every floor where one or more students need to get out, but that is annoying for the students who want to get out on a higher floor. Alternatively, the lift could skip some floors, but that is annoying for the students who wanted to get out on one of those floors.
Specifically, a student will be annoyed on every floor where the lift stops, if the lift has not yet reached the floor on which he or she wants to get out. If the lift skips the floor on which a student wants to get out, he or she will be annoyed on that floor and every higher floor, up to (and excluding) the floor where the lift makes its next stop and the student can finally get out to start walking back down the stairs to his or her destination.For example, if a student wants to get out on the fifth floor, while the lift stops at the second, seventh and tenth floor, the student will be annoyed on floors two, five and six. In total, this student will thus be annoyed on three floors.
Upon entering the lift, every student presses the button corresponding to the floor he or she wants to go to, even if it was already pressed by someone else. The CPU controlling the lift thus gets to know exactly how many students want to get out on every floor.
You are charged with programming the CPU to decide on which floors to stop. The goal is to minimize the total amount of lift anger: that is, the number of floors on which every student is annoyed, added together for all students.
You may ignore all the people who may (want to) enter the lift at any higher floor. The lift has to operate in such a way that every student waiting at the ground floor can reach the floor she or he wants to go to by either getting out at that floor or by walking down the stairs.

数据范围

On the first line one positive number: the number of test cases, at most 100. After that per test case:
one line with a single integer n: the number of floors of the building, excluding the ground floor.
one line with n space-separated integers s[i] for each floor i, the number of students s[i] that want to get out.
N<=1500,1<=s[i]<=1500 N <= 1500 , 1 <= s [ i ] <= 1500

题目分析

第一次打ACM,这样长的英文题面让我很难受,没有什么耐心读下去,简化一下问题就是这样的,有 0N 0 − N 个楼层,你知道每一层下去的人数,如果一个人在第 i i 层下,当电梯停靠在比i低的层 j j 且打开电梯门是,所有在i层下电梯的人都会产生一个单位愤怒值,如果到比自己预期停靠层高的人,不管停不停都会产生一个单位的愤怒值,问所有人下电梯后,一共会产生多少的愤怒值。
f[i] f [ i ] 表示到第 i i 层最少产生的愤怒值

f[i]=min(f[j]+k=ji1(ik)s[k]+k=i+1ns[k])(j<i)

边界条件就是 f[0]=0 f [ 0 ] = 0 ,在每次计算之前维护 s[k] ∑ s [ k ] ks[k] ∑ k ∗ s [ k ] 两个前缀和,这样可以做到 O(1) O ( 1 ) 转移,复杂度 O(N2) O ( N 2 )

#include <bits/stdc++.h>
#define rep( i , l , r ) for( int i = (l) ; i <= (r) ; ++i )
#define per( i , r , l ) for( int i = (r) ; i >= (l) ; --i )
#define erep( i , u ) for( int i = head[(u)] ; ~i ; i = e[i].nxt )
using namespace std;
int _read(){
    char ch = getchar();
    int x = 0 , f = 1 ;
    while( !isdigit( ch ) )
           if( ch == '-' ) f = -1 , ch = getchar();
           else ch = getchar();
    while( isdigit( ch ) )
           x = (ch  - '0') + x * 10 , ch =  getchar();
    return x * f;
}
const int maxn = 2000 + 5;
int f[maxn] , s[maxn] , pre1[maxn] , pre2[maxn]; 
int main(){
//  freopen("test.out" , "w" , stdout );
    int T = _read();
    while( T-- ){
        memset( f , 0x7f , sizeof f );
        int N = _read();
        rep( i , 1 , N ) s[i] = _read();
        rep( i , 1 , N ){
            pre1[i] = pre1[i - 1] + s[i];
            pre2[i] = pre2[i - 1] + s[i] * i;
        }
        f[0] = 0;
        int t1 = 0 , t2 = 0;
        rep( i , 1 , N )
            rep( j , 0 , i - 1 ){
                t1 = t2 = 0;
                t1 = i * ( pre1[i - 1] - pre1[j] );
                t2 = pre2[i - 1] - pre2[j];
                f[i] = min( f[i] , f[j] + t1 - t2 + pre1[N] - pre1[i] );
            }
        cout << f[N] << endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值