如何减少执行时间

Posted

技术标签:

【中文标题】如何减少执行时间【英文标题】:how to reduce execution time 【发布时间】:2013-10-01 15:52:27 【问题描述】:

目前,对于hackerearth.com 上提供的某些测试用例,以下问题需要 3.008** 秒才能执行,其中允许的时间为 3.0 秒,因此出现时间限制错误。请帮助减少执行时间。

问题: Alice 刚刚学会了将两个整数相乘。他想将两个整数 X 和 Y 相乘以形成一个数 Z。为了使问题变得有趣,他将选择 [1,M] 范围内的 X 和 [1,N] 范围内的 Y。帮助他找到他可以通过哪些方式做到这一点。

输入

输入的第一行是测试用例的数量 T。接下来是 T 行。每行有三个空格分隔的整数,数字 Z、M 和 N。

输出

为每个测试用例输出一个整数,表示方法的数量。

约束 1

代码:

#include <iostream>
using namespace std;


int chk_div(long long a,long long b)

if(((a/b) * (b) )==a)return 1;
return 0;


int main()

   int t;
   long  i,j,count;
   long  n,m,z;
   cin>>t;
   while(t--)
   count=0;
    cin>>z>>m>>n;
    if(m>z)m=z;
    if(n>z)n=z;
    if (m>n)m=n;
    for(i=1;i<=m;i++)
    
         if(chk_div(z,i))count++;       
     

   cout<<count<<"\n";
   
return 0;

【问题讨论】:

爱丽丝是一个女孩的名字。 ((a/b) * (b) )==a -> a % b == 0(尽管编译器可能已经为你优化了这个)。另外,只是样式问题,但更喜欢使用min 进行比较,您的代码将更具可读性。 仅供参考,消除空白并不能让它运行得更快。 爱丽丝库珀??? 好的,只是为了解决实际问题,这里有一个很大的提示:en.wikipedia.org/wiki/Integer_factorization 【参考方案1】:

这里的主要性能问题是您的内部循环执行 10^12 迭代的事实。你可以把它减少一百万次到sqrt(z) &lt;= 10^6

这里的诀窍是要注意,Alice 可以写z = x * y 当且仅当他可以写z = y * x。另外,x &lt;= sqrt(z)y &lt;= sqrt(z)。使用这些事实,您最多只能迭代 z 的平方根来计算所有案例。

【讨论】:

【参考方案2】:

我相信这应该可以完成工作(来自@zch 的回答):

#include <iostream>
#include <cmath>

auto MAX = [] (int A, int B) -> bool  return A > B ? A : B; ;
auto MIN = [] (int A, int B) -> bool  return A < B ? A : B; ;

using std::cout;
using std::cin;

int main() 
    long long Z, M, N, T, low, high, temp, div;
    int ans;

    for (cin >> T; T--; ) 

        cin >> Z >> M >> N;
        temp = MIN(M, N);
        low = MIN(sqrt(Z), temp);
        high = MAX(M, N);

        for( ans = 0; low > 0 && (Z / low) <= high; --low ) 
            if ( Z % low == 0) 
                ++ans;
                div = Z / low;
                ans += (div != low && div <= temp);
            
            //cout << temp << " * " << Z / temp << " = " << Z << "\n";
        
        cout << ans << "\n";
    

    return 0;

稍后会添加 cmets

使用 cmets 编写代码

#include <iostream>
#include <cmath>

auto MAX = [] (int A, int B) -> bool  return A > B ? A : B; ;
auto MIN = [] (int A, int B) -> bool  return A < B ? A : B; ;

using std::cout;
using std::cin;

int main() 
    long long Z, M, N, T, low, high, temp, div;
    int ans;

    for (cin >> T; T--; ) 

        cin >> Z >> M >> N;
        temp = MIN(M, N);
        low = MIN(sqrt(Z), temp);//Lowest value <--We start iteration from this number
        high = MAX(M, N); //Maximum value

        for( ans = 0; low > 0 && (Z / low) <= high; --low ) 

            //Number of things going on in this for-loop
            //I will start by explaining the condition:
                //We want to keep iterating until either low is below 1
                // or when the expression (Z / low) > high.
                //Notice that as the value of low approaches 0,
                //the expression (Z / low) approaches inf
            if ( Z % low == 0) 

                //If this condition evaluates to true, we know 2 things:
                    /*Z is divisible by this value of low and 
                        low is in the range of MIN(M,N) <--true*/
                    /*Because of our condition, (Z / low) is
                        within the range of MAX(M, N) <--true*/
                ++ans;
                div = Z / low;

                //This second part checks if the opposite is true i.e.
                    /*the value of low is in the range of
                        MAX(M, N) <--true*/
                    /*the value (Z / low) is in the range of
                        MIN(M, N) <--true only in some cases*/
                ans += (div != low && div <= temp);

                //(div != low) is to avoid double counting
                /*An example of this is when Z, M, N have the values:
                    1000000, 1000000, 1000000
                    The value of low at the start is 1000 */
            
        
        cout << ans << "\n";
    
    return 0;

【讨论】:

一个好的开始。提高速度的下一步可能是考虑 Z。 @Smac89 感谢代码工作......但你不能解释一下“ans += (div != low && div @MahendraChandwani 以下是代码在使用 Z = 1000000、M = 1000000、N = 1000000 的值运行时生成的values。从示例中可以看出,生成的第一个输出是1000 * 1000。这就是说 X 的值为 1000 而 Y 的值为 1000 来生产产品 Z。现在如果我要交换 X 和 Y 的值,这是多余的,因为 X 仍然是 1000 而 Y 仍然是 1000。所以没有必要多次计算这种情况,因为我们没有得到不同的 X 和 Y 值 @MahendraChandwani 为了最大化我们获得的组合数量,我们尝试查看一些较高的最终值是否也可以放入较小的存储桶中。这就是为什么我们这样做div &lt;= temp。随着迭代的继续 div 变得越来越大,这样做,我们能够在它变大之前获得尽可能多的匹配。请注意,这行简单的代码 ans += (div != low &amp;&amp; div &lt;= temp); 使我们不必利用我们已经获得的值进行两次迭代。【参考方案3】:

事实上,你必须以不同的方式解决问题:

求素数分解:

所以Z = A^a * B^b * ... * P^pA, B, .., P 素数

所以你只需要计算来自a, b, ... p的可能性数量。

(因此结果取决于 M&N 约束,最高可达 (1 + a) * (1 + b) * ... * (1 + p))。

【讨论】:

您还必须限制 M 和 N 指定的可能性。 @EricPostpischil:根据给定的约束,结果是max(M) == max(N) == Z 问题陈述表明 Z、M 和 N 从输入中读取为单独的整数。 M 和 N 可能小于或大于 Z。唯一的限制是 Z、M 和 N 中的每一个都至少为 1,并且最多为 10**12。 修正后,这对解决问题有何帮助? @zch:对于大多数 Z 值,分解 Z 极大地减少了必须测试的案例数量。【参考方案4】: 你的 if(((a/b) * (b) ) == a) 返回 1;将始终返回 1。为什么要将 A 与 B (a/b) 相除,然后将结果乘以 B。这是模棱两可的,因为当您说 (a/b) * (b) 时,您的答案将是 A。 B`s 会互相抵消,你只剩下 A 作为你的答案。所以基本上你是在比较 A == A,这是真的。

【讨论】:

/ 对于整数类型是整数除法,丢弃余数。例如9 / 4 == 2. 重点是您将 A 除以 B,然后将结果与 B 相乘。我不确定 Double 是否受到限制或不应该在此问题中用于准确性目的。我认为这是留给编码人员的。 (9 / 4) * 4 将提供2 * 4 != 9。这个检查是正确的,不过最好写成a % b == 0 如果是这种情况,我建议使用 mod 公式。即使这可能对性能问题没有帮助。但它可能会更快。我确信您可以使用 mod 公式的一行指令来完成,这与需要两行指令的计算不同。 他也可以试试 ((a/b) * (b) == a) ? 1:0;就限制指令总数而言。

以上是关于如何减少执行时间的主要内容,如果未能解决你的问题,请参考以下文章

如何减少此脚本的执行时间?

如何减少这个mysql查询执行时间

如何减少 SVM 的执行时间

如何在 spark-submit 之前触发催化剂优化器以减少执行时间?

如何减少查询执行时间 vb.net webform

如何减少因子循环的执行时间和周期数?和/或代码大小?