1397B - Power Sequence 幂序列(思路+证明公式)

题意

Let’s call a list of positive integers a0,a1,…,an−1a0,a1,…,an−1 a power sequence if there is a positive integer cc, so that for every 0≤i≤n−10≤i≤n−1then ai=ciai=ci.

Given a list of nn positive integers a0,a1,…,an−1a0,a1,…,an−1, you are allowed to:

  • Reorder the list (i.e. pick a permutation pp of {0,1,…,n−1}{0,1,…,n−1} and change aiai to apiapi), then
  • Do the following operation any number of times: pick an index ii and change aiai to ai−1ai−1 or ai+1ai+1 (i.e. increment or decrement aiai by 11) with a cost of 11.

Find the minimum cost to transform a0,a1,…,an−1a0,a1,…,an−1 into a power sequence.

Input

The first line contains an integer nn (3≤n≤1053≤n≤105).

The second line contains nn integers a0,a1,…,an−1a0,a1,…,an−1 (1≤ai≤1091≤ai≤109).

Output

Print the minimum cost to transform a0,a1,…,an−1a0,a1,…,an−1 into a power sequence.

思路:
  • 首先:升序重排一定是最优的,因为最终的Power Sequence 升序,因此我们升序排列一定最贴合最终序列。

对于 q , n q,n q,n,假设 q = 10 , n = 100 q=10,n=100 q=10,n=100,最后一项就是 q = 1 0 100 q=10^{100} q=10100,非常之大,明显不符合题意,因此引发我们思考,去寻找 q q q的取值范围。

下面简单证明一下 q q q的取值范围

对于长度为n的序列 [ a 1 . . . . . a i ] [a_1.....a_i] [a1.....ai],最起码的我们可以让其全部变为1满足Power Sequence,让其全变为的花费为 s u m = ∑ i = 1 n ( a i − 1 ) sum=\sum_{i=1}^{n}(a_i-1) sum=i=1n(ai1)

,现在来确定一下sum的取值范围,当 a i = 1 0 9 a_i=10^9 ai=109 s u m sum sum为最大花费,即 s u m < n ∗ 1 0 9 sum<n*10^9 sum<n109。最终形成的Power Sequence,公比 q = c q=c q=c,其第 n n n项为最大值 a n = q n − 1 a_n=q^{n-1} an=qn1,如果 a n > s u m a_n>sum an>sum那么就毫无意义,因此需要满足 a n < = s u m an<=sum an<=sum,即 q n − 1 < = s u m < n ∗ 1 0 9 q^{n-1}<=sum<n*10^9 qn1<=sum<n109,化简一下就可以得到q的取值范围
1 < = q < n ∗ 1 0 9 n − 1 1<=q<\sqrt[n-1]{n*10^9} 1<=q<n1n109
我们枚举q难道会超时吗?其实不然,我们时间复杂度为 O ( n ∗ q ) = O ( n ∗ n ∗ 1 0 9 n − 1 ) O(n*q)=O(n*\sqrt[n-1]{n*10^9}) O(nq)=O(nn1n109 ),n=3的时候

我们发现n最小值为3,即
1 < = q < n ∗ 1 0 9 n − 1 < = 3 ∗ 1 0 9 < 1 0 5 1<=q<\sqrt[n-1]{n*10^9}<=\sqrt{3*10^9}<10^5 1<=q<n1n109 <=3109 <105
n=4的时候 q < 1 e 4 q<1e4 q<1e4,很明显递减了(也可以对公式求导进行直接验证),因此我们时间上限为
3 ∗ 1 0 9 < 1 0 5 \sqrt{3*10^9}<10^5 3109 <105
综上:不会超时

算法

枚举n和q算出即可,唯一注意的是
1 < = q < n ∗ 1 0 9 n − 1 < = 3 ∗ 1 0 9 < 1 0 5 1<=q<\sqrt[n-1]{n*10^9}<=\sqrt{3*10^9}<10^5 1<=q<n1n109 <=3109 <105
后面式子c++会自动向下取整,因此等式修改为
1 < q < = [ n ∗ 1 0 9 n − 1 ] < = [ 3 ∗ 1 0 9 ] < 1 0 5 1<q<=[\sqrt[n-1]{n*10^9}]<=[\sqrt{3*10^9}]<10^5 1<q<=[n1n109 ]<=[3109 ]<105

代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
int r[N];
int main() {
    int n;
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>r[i];
    }
    sort(r,r+n);
    ll res=LLONG_MAX;
    ll up=pow(1e9*n,1.0/(n-1)); //最大值
    for(ll q=1;q<=up;q++){
        ll x=1,sum=0;
        for(int i=0;i<n;i++){
            sum+=abs(r[i]-x);
            x*=q;
        }
        res=min(res,sum);
    }
    cout<<res<<endl;
}


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 可以使用一个循环来计算这个数列的和,每次循环加上或者减去当前数值即可。以下是 Python 代码实现: ```python def calculate_sum(): result = 0 sign = 1 for i in range(1, 100): if i % 3 == 0: sign = -1 result += sign * i return result ``` 代码中,`result` 变量用来记录当前数列的和,`sign` 变量用来记录当前数值的正负号,初始值为 1。当当前数值是 3 的倍数时,需要改变符号,因此将 `sign` 变为 -1。循环从 1 到 99 进行遍历,每次加上或者减去当前数值即可。最后返回 `result` 变量即可得到结果。 ### 回答2: 要编写一个函数来计算给定数值结果的序列,可以按照以下方式实现: 首先,我们可以观察到序列中有一个规律,即每个数字后面的三个数字与之前的数字具有相应的关系。 根据观察到的规律,我们可以编写一个函数来计算结果。函数的输入可以是序列中的数字的范围,如1到99,输出可以是对应的结果序列。 具体来说,可以按照以下步骤实现函数: 1. 定义一个空的结果列表,用于存储计算后的数字序列。 2. 使用一个循环来遍历给定范围内的每个数字。 3. 在循环中,对于每个数字,首先判断其是否为偶数。如果是偶数,则将其添加到结果列表中。 4. 如果数字为奇数,则将其添加到结果列表中,然后添加连续的三个数字(当前数字的下一个数字,以及之后的两个数字)。 5. 继续循环,直到遍历完给定范围内的所有数字。 6. 返回结果列表作为函数的输出。 例如,如果函数的输入范围为1到99,函数的输出将是 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, ..., 97, 98, 99]。 请注意,上述方法实际上是根据规律进行数学计算,而不是编写一个循环来模拟序列的生成过程。这种方法可以有效地计算结果,而不需要遍历大量的数字。 ### 回答3: 可以编写一个函数来计算出如上数字序列的结果。该函数的主要思路是通过循环来迭代每个数字,并利用条件语句判断是否需要进行特殊的处理。 下面是一个可能的函数实现: ```python def calculate_sequence(): result = [] # 存储结果的列表 for i in range(1, 100): # 迭代每个数字 if i % 4 == 0: # 如果当前数字是4的倍数 result.append(i * -1) # 将其加入结果列表,并取其相反数 else: result.append(i) # 否则将当前数字加入结果列表 return result # 调用函数获取结果 sequence_result = calculate_sequence() # 打印结果 print(sequence_result) ``` 该函数首先创建一个空的列表 `result` 来存储结果。然后通过 `for` 循环迭代从1到99的每个数字。在循环中,通过使用模运算符 `%`,判断当前数字是否是4的倍数。如果是4的倍数,将其加入结果列表,并且取其相反数;否则,将当前数字加入结果列表。 最后,该函数返回结果列表 `result`。可以直接调用该函数,将结果打印出来。 运行该函数后,将输出结果:`[1, 2, 3, -4, -5, -6, 7, 8, 9, -10, -11, -12, 13, 14, 15, ...]`

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值