2021蓝桥杯省赛 C++ A组C题 B组D题 货物摆放(暴力求解O(n^(2/3)))

文章目录

    • 题目
    • 解析
      • 引入
      • 证明过程
      • 完整代码
      • 计算时间复杂度
      • 运行结果
    • 小结

题目

2021蓝桥杯省赛 C++ A组C题 B组D题 货物摆放(暴力求解O(n^(2/3)))_第1张图片
图片来源2021蓝桥杯省赛 C++ A组 个人部分题解

解析

引入

受暴力求解素数判断的影响(遍历2到 n \sqrt{n} n ),有了这题的思路
直接暴力是解不出的
不过缩小一点范围就可以暴力出来了
只需要两个for循环,第一层从 1 1 1 n 3 \sqrt[3] {n} 3n ,第二层从 i i i n i \sqrt{\dfrac{n}{i}} in

证明过程

设目标长宽高为 a 、 b 、 c a、b、c abc
则有 a b c = n abc=n abc=n
不妨设 a ≤ b ≤ c a\leq b\leq c abc
a 、 b 、 c a、b、c abc都是大于1的正整数

由上述条件可以推出

a 3 ≤ a b c = n a^{3} \leq abc = n a3abc=n

a ≤ n 3 a \leq \sqrt[3]{n} a3n

即a的最大值为 n 3 \sqrt[3]{n} 3n
同理当a取某个特殊值时

即当 a = i a=i a=i

又可推出

b 2 ≤ b c = n / a = n / i b^{2} \leq bc = n/a=n/i b2bc=n/a=n/i

i ≤ b ≤ n i i\leq b \leq \sqrt{\dfrac{n}{i}} ibin

即b的最大值为 n i \sqrt{\dfrac{n}{i}} in ,最小值为 i i i

这样复杂度就降低了很多(虽然还是很高)
最后写个排列特判就好了

int cal(ll a, ll b, ll c) {
     
    if(a==b && b==c && a==c) return 1;
    else if(a!=b && a!=c && b!=c) return 6;
    else return 3;
}

完整代码

#include 
#include 
using namespace std;

typedef long long ll;

int cal(ll a, ll b, ll c) {
     
    if(a==b && b==c && a==c) return 1;
    else if(a!=b && a!=c && b!=c) return 6;
    else return 3;
}

int main() {
     
    int ans = 0;
    ll n = 2021041820210418, tmp;
    ll crn = ll(pow(n, 1/3.0));
    cout << crn << endl;
    for(ll i = 1; i <= crn; ++i) {
     
        if(n % i) continue;
        tmp = n / i;
        for(ll j = i; j <= ll(sqrt(tmp)); ++j) {
     
            if(tmp % j) continue;
            ans += cal(i, j, tmp/j);
        }
    }
    cout << ans << endl;
}

计算时间复杂度

设计算次数N,S是n中小于 n 3 \sqrt[3]{n} 3n 的因数集合
由于当n%i==0满足时才会由下一个循环

S = { x ∣ n m o d    x = 0 且 x < n 3 } N = ∑ i ∈ S ( n i − i ) \begin{aligned} S&=\{x|n \mod x=0 且 x<\sqrt[3]{n} \} \\ N&= \sum ^{}_{i\in S}(\sqrt{\dfrac{n}{i}}-i) \end{aligned} SN={ xnmodx=0x<3n }=iS(in i)

因 为 n i ≥ n 3 ≥ i 所 以 n i − i ≥ 0 \begin{aligned} &因为 &\sqrt{\dfrac{n}{i}} \geq \sqrt[3]{n} \geq i\\ &所以 &\sqrt{\dfrac{n}{i}}-i \geq 0 \end{aligned} in 3n iin i0

简单的放缩

所 以 N ≤ ∑ i = 1 ⌈ n 3 ⌉ ( n i − i ) (见文章小结4) \begin{aligned} &所以 &N \leq \sum ^{\lceil \sqrt[3]{n} \rceil}_{i=1}(\sqrt{\dfrac{n}{i}}-i) \tag{见文章小结4} \end{aligned} Ni=13n (in i)(4)

∑ i = 1 ⌈ n 3 ⌉ ( n i − i ) = ∑ i = 1 ⌈ n 3 ⌉ ( n i ) − ∑ i = 1 ⌈ n 3 ⌉ i = ∑ i = 1 ⌈ n 3 ⌉ ( n i ) − ( ⌈ n 3 ⌉ ) 2 + ⌈ n 3 ⌉ 2 ≤ ∑ i = 1 ⌈ n 3 ⌉ ( n i ) − n 2 / 3 + n 1 / 3 2 = n ( ∑ i = 2 ⌈ n 3 ⌉ 1 i + 1 ) − n 2 / 3 + n 1 / 3 2 ≤ n ( ∫ 1 ⌈ n 3 ⌉ 1 i d x + 1 ) − n 2 / 3 + n 1 / 3 2 = 2 n ( ⌈ n 3 ⌉ − 1 + 1 ) − n 2 / 3 + n 1 / 3 2 ≈ 2 n ( n 1 / 6 ) − n 2 / 3 + n 1 / 3 2 = 4 n 2 / 3 − n 2 / 3 − n 1 / 3 2 = 3 n 2 / 3 − n 1 / 3 2 \begin{aligned} \sum ^{\lceil \sqrt[3]{n} \rceil}_{i=1}(\sqrt{\dfrac{n}{i}}-i) &= \sum ^{\lceil \sqrt[3]{n} \rceil}_{i=1}(\sqrt{\dfrac{n}{i}}) - \sum ^{\lceil \sqrt[3]{n} \rceil}_{i=1}i \\ &=\sum ^{\lceil \sqrt[3]{n} \rceil}_{i=1}(\sqrt{\dfrac{n}{i}}) - \dfrac{(\lceil \sqrt[3]{n} \rceil)^2+\lceil \sqrt[3]{n} \rceil}{2} \\ &\leq \sum ^{\lceil \sqrt[3]{n} \rceil}_{i=1}(\sqrt{\dfrac{n}{i}}) - \dfrac{n^{2/3}+n^{1/3}}{2}\\ &=\sqrt{n}(\sum ^{\lceil \sqrt[3]{n} \rceil}_{i=2}\dfrac{1}{\sqrt{i}}+1) - \dfrac{n^{2/3}+n^{1/3}}{2}\\ &\leq \sqrt{n}(\int ^{\lceil \sqrt[3]{n} \rceil}_{1}\dfrac{1}{\sqrt{i}}dx+1) - \dfrac{n^{2/3}+n^{1/3}}{2}\\ &= 2\sqrt{n}(\sqrt{\lceil \sqrt[3]{n} \rceil} - 1+1) - \dfrac{n^{2/3}+n^{1/3}}{2}\\ &\approx 2\sqrt{n}(n^{1/6}) - \dfrac{n^{2/3}+n^{1/3}}{2} \\ &=\dfrac{4n^{2/3} - n^{2/3} - n^{1/3}}{2}\\ &=\dfrac{3n^{2/3} - n^{1/3}}{2} \end{aligned} i=13n (in i)=i=13n (in )i=13n i=i=13n (in )2(3n )2+3n i=13n (in )2n2/3+n1/3=n (i=23n i 1+1)2n2/3+n1/3n (13n i 1dx+1)2n2/3+n1/3=2n (3n 1+1)2n2/3+n1/32n (n1/6)2n2/3+n1/3=24n2/3n2/3n1/3=23n2/3n1/3

所 以 N ≤ 3 n 2 / 3 − n 1 / 3 2 所以N \leq \dfrac{3n^{2/3} - n^{1/3}}{2}\\ N23n2/3n1/3

所 以 时 间 复 杂 度 O ( n 2 / 3 ) 所以时间复杂度O(n^{2/3}) O(n2/3)

复杂度从O( n 2 n^2 n2)优化到 O ( n 2 / 3 ) O(n^{2/3}) O(n2/3)直接暴力就可以了
不过还是要跑个1秒多

时间插值计算运行时间

#include 
#include 
#include 
using namespace std;

typedef long long ll;

int cal(ll a, ll b, ll c) {
     
    if(a==b && b==c && a==c) return 1;
    else if(a!=b && a!=c && b!=c) return 6;
    else return 3;
}

int main() {
     
    int ans = 0;
    clock_t startTime,endTime;
    ll n = 2021041820210418, tmp;
    ll crn = ll(pow(n, 1/3.0));
    cout << "三次根号n(取整)=" <<crn << endl;
    startTime = clock();
    for(ll i = 1; i <= crn; ++i) {
     
        if(n % i) continue;
        tmp = n / i;
        for(ll j = i; j <= ll(sqrt(tmp)); ++j) {
     
            if(tmp % j) continue;
            ans += cal(i, j, tmp/j);
        }
    }
    endTime = clock();
    cout << ans << endl;
    cout << "The run time is:" <<(double)(endTime - startTime) / CLOCKS_PER_SEC << "s" << endl;
}

运行结果

在这里插入图片描述

答案2430

小结

  1. 当时考场上都看懵了,由于技术力不足,时间复杂度下不来了(坐等dalao优化)
  2. 考场上我是用python计算的 n 3 \sqrt[3]{n} 3n (结果是126432.41496378921)
  3. 今年蓝桥杯好难,被ACM赛制带坏了,忘了在OI赛制上抢分了,省四预定
  4. T ≤ ∑ i = 1 ⌈ n 3 ⌉ ( n i − i ) T \leq \sum ^{\lceil \sqrt[3]{n} \rceil}_{i=1}(\sqrt{\dfrac{n}{i}}-i) Ti=13n (in i)这一步放得有点大了(我是数学菜鸡 ),有没有dalao优化一下(不然这题这么会只跑1秒多)
  5. 2021年4月20日更新,修改了复杂度的逻辑错误,发现才 O ( n 2 / 3 ) O(n^{2/3}) O(n2/3)

你可能感兴趣的:(蓝桥杯,algorithm,算法,c++,c语言)