AtCoder:guruguru(思维 & 差分)

探讨了通过设置最优初始亮度水平来最小化调整灯亮度所需的按键次数的算法。利用差分数组实现O(n)复杂度。

E - guruguru


Time limit : 2sec / Memory limit : 256MB

Score : 700 points

Problem Statement

Snuke is buying a lamp. The light of the lamp can be adjusted to m levels of brightness, represented by integers from 1 through m, by the two buttons on the remote control.

The first button is a "forward" button. When this button is pressed, the brightness level is increased by 1, except when the brightness level is m, in which case the brightness level becomes 1.

The second button is a "favorite" button. When this button is pressed, the brightness level becomes the favorite brightness level x, which is set when the lamp is purchased.

Snuke is thinking of setting the favorite brightness level x so that he can efficiently adjust the brightness. He is planning to change the brightness n1 times. In the i-th change, the brightness level is changed from ai to ai+1. The initial brightness level is a1. Find the number of times Snuke needs to press the buttons when x is set to minimize this number.

Constraints

  • 2n,m105
  • 1aim
  • aiai+1
  • nm and ai are integers.

Input

Input is given from Standard Input in the following format:

n m
a1 a2an

Output

Print the minimum number of times Snuke needs to press the buttons.


Sample Input 1

Copy
4 6
1 5 1 4

Sample Output 1

Copy
5

When the favorite brightness level is set to 12345 and 6, Snuke needs to press the buttons 89756 and 9 times, respectively. Thus, Snuke should set the favorite brightness level to 4. In this case, the brightness is adjusted as follows:

  • In the first change, press the favorite button once, then press the forward button once.
  • In the second change, press the forward button twice.
  • In the third change, press the favorite button once.

Sample Input 2

Copy
10 10
10 9 8 7 6 5 4 3 2 1

Sample Output 2

Copy
45
题意:有个M个档的台灯,有N个目标档,需要按顺序调到相应目标档,每次只能按按钮一步一步进档,或者按一下按钮跳到x档,问x档初始化为最优档时,完成任务按的最少次数按钮。

思路:假设从a[i]到a[i+1]档,可以按a[i+1]-a[i]次,假如x设置在其中间位置,只需按a[i+1]-x+1次即可,那么可以将每个a[i]和a[i+1]看成一条线段,只要x设置在线段上,这次操作就有相应的次数减少,减少的次数为x-a[i]-1次,x在线段外即对当前操作无影响,那么b数组将线段上每个值都加上a[i]+1,同时另开数组c在同样线段上各个值+1,表示x设这个位置就能减少次数,最后遍历一下就能知道x设置在位置i能减少的总次数了,上述操作用差分数组解决,复杂度O(n)。

# include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 1e5;
LL a[maxn+3]={0}, b[maxn+3]={0}, c[maxn+3]={0};
int main()
{
    LL sum = 0;
    int n, m;
    scanf("%d%d%lld",&n,&m,&a[1]);
    for(int i=2; i<=n; ++i)
    {
        scanf("%lld",&a[i]);
        if(a[i] > a[i-1])
        {
            sum += a[i]-a[i-1];
            b[a[i-1]+1] += a[i-1]+1;
            b[a[i]+1] -= a[i-1]+1;
            ++c[a[i-1]+1];
            --c[a[i]+1];
        }
        else
        {
            sum += m-a[i-1]+a[i];
            b[a[i-1]+1] += a[i-1]+1;
            ++c[a[i-1]+1];
            b[1] -= m-a[i-1]-1;
            ++c[1];
            b[a[i]+1] += m-a[i-1]-1;
            --c[a[i]+1];
        }
    }
    for(int i=1; i<=m; ++i)
        b[i] += b[i-1], c[i] += c[i-1];
    LL ans = 0;
    for(int i=1; i<=m; ++i)
        ans = max(ans,i*1LL*c[i]-b[i]);
    printf("%lld\n",sum-ans);
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值