Getting Zero

文章讲述了如何通过两种操作将整数a_i变回0,即加1或乘以2模32768。给出了一个贪心策略,利用2的因子数和预处理的1到32768的2的因子数表来计算每个数所需的最少操作次数。
摘要由CSDN通过智能技术生成

# Getting Zero

## 题面翻译

给定 $v$,可以将 $v$ 如下操作:

变成 $(v + 1) \% 32768$ 或者 $2\times v\%32768$,

求最少经过几次操作能将 $v$ 变回 $0$。

## 题目描述

Suppose you have an integer $ v $ . In one operation, you can:

- either set $ v = (v + 1) \bmod 32768 $
- or set $ v = (2 \cdot v) \bmod 32768 $ .

You are given $ n $ integers $ a_1, a_2, \dots, a_n $ . What is the minimum number of operations you need to make each $ a_i $ equal to $ 0 $ ?

## 输入格式

The first line contains the single integer $ n $ ( $ 1 \le n \le 32768 $ ) — the number of integers.

The second line contains $ n $ integers $ a_1, a_2, \dots, a_n $ ( $ 0 \le a_i < 32768 $ ).

## 输出格式

Print $ n $ integers. The $ i $ -th integer should be equal to the minimum number of operations required to make $ a_i $ equal to $ 0 $ .

## 样例 #1

### 样例输入 #1

```
4
19 32764 10240 49
```

### 样例输出 #1

```
14 4 4 15
```

## 提示

Let's consider each $ a_i $ :

- $ a_1 = 19 $ . You can, firstly, increase it by one to get $ 20 $ and then multiply it by two $ 13 $ times. You'll get $ 0 $ in $ 1 + 13 = 14 $ steps.
- $ a_2 = 32764 $ . You can increase it by one $ 4 $ times: $ 32764 \rightarrow 32765 \rightarrow 32766 \rightarrow 32767 \rightarrow 0 $ .
- $ a_3 = 10240 $ . You can multiply it by two $ 4 $ times: $ 10240 \rightarrow 20480 \rightarrow 8192 \rightarrow 16384 \rightarrow 0 $ .
- $ a_4 = 49 $ . You can multiply it by two $ 15 $ times.

思路:

贪心思想,有两条路可走,那么将这两条路拆开分析,第一条路,直接加一;第二条路,直接乘以二。在mod上考虑我们发现,32768为2的15次方,那么看第二条路我们发现是直接增加2的因子数,最多15次就能倍32768整除,也就变成了k*2的次方形式,mod后得k,最多不超过15次;那么由此看第一条路。我们发现是为了增加2的因子数才使用这条路,因为1到32768的数中包含2的次方数不同,进而我们使用打表的方法,预处理出1到32768的所有2的因子数,再进行遍历,注意,因为我们的次数最多不超过15次,所以只遍历15次即可。别忘了取mod。

AC代码如下:

// 蓝桥杯.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <algorithm>
#include <cmath>
#include<vector>
#include <string>
using namespace std;
int pan2(int num)
{
    int c;
    if (num == 0) c = 15;
    else c = log2(num&(-num));
    return c;
}
int l1(int num)
{
    return (15-pan2(num));
}
int l2(int num, int* a)
{
    int min = 1000000;
    int c = 0;
    for (int i = 1; i <= 15; i++)
    {
        c++;
            
        if (min > 15 - a[i + num] + c) min = 15 - a[i + num] + c;
       
    }
    return min;
}
int main()
{
    
    int t;
    t = 1;
    while (t--)
    {
        int n;
        cin >> n;
        int a[33000] = { 0 };
        
        for (int i = 1; i <= 33000; i++)
        {            
            a[i] = pan2(i);
        }
        
        
        for (int i = 0; i < n; i++)
        {
            int c1 = 0;
            int c2 = 0;
            int num;
            cin >> num;
            num = num % 32768;
            c1 = l1(num);
            c2 = l2(num,a);
            cout << min(c1, c2)<<' ';
        }
        
        
    }
    return 0;
    
    
}

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值