问题 A: 复杂度分析(Ⅰ)
时间限制: 1 Sec 内存限制: 128 MB
题目描述
分析如下代码
for(i=1;i<n;i++)
for(j=1;j<i;j++)
for(k=1;k<j;k++)
printf("\n");
问printf语句共执行了几次?这段代码执行完以后i+j+k值为多少?
输入
由多行组成,每行一个整数n, 1<= n <= 3000
输出
对每一行输入,输出对应的一行,包括空格分开的两个整数,分别代表printf语句的执行次数以及代码执行完以后i+j+k的值, 如果值不确定,输出"RANDOM"取代值的位置
样例输入
6
样例输出
10 15
计算过程
1.运算中,发现若仅使用整形变量,会导致计算结果出现问题:
1.1情况一:数据超出整型变量计算范围导致空间超限
1.2情况二:整型变量数据范围小导致计算所用时间过长运算超时,所以需要使用超长整型变量扩大运算范围,节省运行时间
2.1当n小于或等于3时及时n运行为2,最后一句执行printf所相连的for循环不满足条件无法进入,所以执行次数为0,循环次数为1+2+3=6
2.2当n大于3时若使用题干所给代码时间复杂度为O(n3),此时运算结果显示超时,所以需要通过数学方法计算将时间复杂度简化,通过循环次数的计算,可将题干所给三层循环简化为一层循环的数学计算式
这段代码是一个三层嵌套循环,其逻辑是打印出换行符。下面是如何计算 printf
语句执行次数、i+j+k
值的总和以及代码的运行逻辑:
-
计算
printf
执行次数:- 外层循环
i
从 1 迭代到n-1
(因为i < n
)。 - 中层循环
j
从 1 迭代到i-1
(因为j < i
)。 - 内层循环
k
从 1 迭代到j-1
(因为k < j
)。 - 对于每一个
i
,j
的取值范围是从 1 到i-1
,而k
的取值范围是从 1 到j-1
。 - 因此,
printf
执行次数的总和是所有可能的(i, j, k)
组合的数量。
- 外层循环
-
计算
i+j+k
值的总和:- 要计算
i+j+k
的总和,可以分别计算i
、j
和k
的总和,然后相加。
- 要计算
-
运行逻辑:
- 对于每一层循环,
i
、j
和k
都是逐步增加的,但每一层的增加都是基于内层循环的完成。 - 当
k
达到它的上限(j-1
)时,k
重置为 1,j
增加 1。 - 当
j
达到它的上限(i-1
)时,j
重置为 1,i
增加 1。
- 对于每一层循环,
下面是具体的计算方法:
i
的总和是等差数列求和:(1 + 2 + ... + (n-1))
。- 对于每一个
i
,j
的总和是:(1 + 2 + ... + (i-1))
。 - 对于每一个
(i, j)
对,k
的总和是:(1 + 2 + ... + (j-1))
。
printf
执行次数的总和可以用下面的公式计算:
[ \text{总次数} = \sum_{i=1}^{n-1} \sum_{j=1}^{i-1} \sum_{k=1}^{j-1} 1 ]
i+j+k
值的总和可以用下面的公式计算:
[ \text{总和} = \sum_{i=1}^{n-1} i \left( \sum_{j=1}^{i-1} j \left( \sum_{k=1}^{j-1} k \right) \right) ]
由于这是一个立方求和问题,计算起来相对复杂,通常需要使用数学工具或编程方法来求解。
注意:上述公式中的求和项是连续整数的和,可以使用等差数列求和公式简化计算。对于 i
、j
和 k
的总和,可以使用以下公式:
[ \text{某个变量的总和} = \frac{n(n + 1)(2n + 1)}{6} - \frac{n^3}{2} ]
其中 n
是该变量在最外层循环中的上限减 1。对于 k
,上限是 j-1
,所以 n
应该是 i-1
和 j-1
。这个公式是连续整数和的求和公式,但需要适当调整以适应嵌套循环的边界条件。
AC代码
部分实现
代码如下(n<=3):
if( n <= 3)
{
if( n < 3 )
printf("0 RANDOM\n");
else printf("0 6\n");
}
代码如下(n>3):
else
{
sum = 3*n - 3;
for( i = 3,k = 1; i < n ; i++,k++)
{
a = k + a;
t = t + a;
}
printf("%lld %lld\n",t,sum);
}
}
AC代码
代码如下:
#include<bits/stdc++.h>
using namespace std;
int main()
{
//运算中,发现若仅使用整形变量,会导致计算结果出现问题,情况一:数据超出整型变量计算范围导致空间超限,情况二:整型变量数据范围小导致计算所用时间过长运算超时,所以需要使用超长整型变量扩大运算范围,节省运行时间
int n;
while( scanf("%d",&n)!= EOF )
{
long long t=0,sum,i,k,a=0;
//当n小于或等于3时及时n运行为2,最后一句执行printf所相连的for循环不满足条件无法进入,所以执行次数为0,循环次数为1+2+3=6
if( n <= 3)
{
if( n < 3 )
printf("0 RANDOM\n");
else printf("0 6\n");
}
else
//当n大于3时若使用题干所给代码时间复杂度为O(n3),此时运算结果显示超时,所以需要通过数学方法计算将时间复杂度简化,通过循环次数的计算,可将题干所给三层循环简化为一层循环的数学计算式
{
sum = 3*n - 3;
for( i = 3,k = 1; i < n ; i++,k++)
{
a = k + a;
t = t + a;
}
printf("%lld %lld\n",t,sum);
}
}
return 0;
}