当前位置: 代码迷 >> 综合 >> POJ 1701 Dissatisfying Lift (数学推导,枚举)
  详细解决方案

POJ 1701 Dissatisfying Lift (数学推导,枚举)

热度:30   发布时间:2023-12-13 19:53:01.0

题目意思:
m层楼,每层i楼有 K[i] 个住客,电梯只能停留在某一层,然后所有的住客,由该楼层走楼梯回家。
加入走楼梯的的层数为N,上楼的不满意度 为 a * N + .05 * N * (N - 1), 下楼的则为
b* N + .05 * N * (N - 1)。题目问,电梯停留在那一层的不满意度总和最小。

参考网上老哥的公式推导 https://ishare.iask.sina.com.cn/f/avsXq1tzeSc.html
本题要点:
1、d[p] 表示电梯停留在p层的不满意度
比较 d[p + 1] 和 d[p] 的差值,分解为三部分
第一部分:s1 = sum{1 * K[1], 2 * K[2], …, n * K[n]}, 这部分是常数值
第二部分:用数组 s2[MaxN] 存储,假设电梯停留在p层
s2[p] = (b + p) * sum{K[1], K[2], … , K[p]}
第三部分:用数组 s3[MaxN] 存储, 假设电梯停留在p层
s3[p] = (a - p - 1) * sum{K[p + 1], K[p + 1], … , K[n]}

d[p + 1] - d[p] = -s1 + s2[p] - s3[p]
d[p + 1] = d[p] + -s1 + s2[p] - s3[p]	//递推公式

2、先计算 s1, 复杂度 O(n);
同理数组 s2, s3, 复杂度也是 O(n);
先计算 电梯停留在一层的 d[1], 利用递推公式可以计算每一层 的 不满意度d[p],
记录最小值即可

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int MaxN = 10010;
int Test, n, a, b;
long long K[MaxN];
long long s1, k_sum;
long long sumi[MaxN];
long long s2[MaxN];
long long s3[MaxN];void init()
{
    s1 = 0;for(int i = 1; i <= n; ++i){
    s1 += K[i] * i;	}memset(s2, 0, sizeof(s2));memset(s3, 0, sizeof(s3));for(int i = 1; i <= n; ++i){
    s2[i] = (b + i) * sumi[i];s3[i] = (a - i - 1) * (k_sum - sumi[i]);}
}void solve()
{
    long long d = 0, ans = -1;//电梯停留在1层, 计算不满意值 dfor(int i = 2; i <= n; ++i){
    d += a * (i - 1) * K[i];d += K[i] * (i - 1) * (i - 2) / 2; }
// printf("d = %lld\n", d);ans = d;int floor = 1;for(int i = 2; i <= n; ++i){
    d = d - s1 + s2[i - 1] - s3[i - 1];if(d < ans){
    ans = d;floor = i;}}printf("%d\n", floor);
}int main()
{
    scanf("%d", &Test);while(Test--){
    k_sum = 0;memset(sumi, 0, sizeof(sumi));scanf("%d%d%d", &n, &a, &b);for(int i = 1; i <= n; ++i){
    scanf("%lld", &K[i]);		k_sum += K[i];sumi[i] = K[i] + sumi[i - 1];
// printf("sumi[%d] = %lld\n", i, sumi[i]);}init();solve();}return 0;
}/* 1 5 3 2 1 1 1 1 1 *//* 3 */