【问题标题】: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

标签: c++ algorithm time


【解决方案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;就限制指令总数而言。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-12-31
    • 2017-03-03
    • 2016-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多