【问题标题】:Optimizing a Standard Iterative Algorithm [duplicate]优化标准迭代算法
【发布时间】:2013-12-21 07:32:50
【问题描述】:

关于这里的问题挑战: Link

#include <iostream>

using namespace std;


int main() {
    int T,*x,i,j,k,a,res,pres;
    long Q,N,p,q;
    cin>>T;
    for(k=0;k<T;k++)
    {
        cin>>N>>Q;
        x=new int[N];
        for(i=0;i<N;i++)
        {
            cin>>x[i];
        }
        for(i=0;i<Q;i++)
        {
            pres=-999;
            cin>>a>>p>>q;
            for(j=p-1;j<q;j++)
            {
                res=a xor x[j];
                if(pres<res)
                {
                    pres=res;
                }
            }
            cout<<pres<<endl;

        }
        delete [] x;
    }
    return 0;
}

在较大的问题(N=100000)(N、Q、T 最大化)上,我的时间限制已超过(暗示问题可以优化)。我想我需要使用某种预处理来优化算法。对于整个问题,我的解决方案是 O(NQT)。该问题需要评估查询中给定限制的所有可能的 XOR。因此,问题需要进行 (q-p)[Can be at max N] 次查询。我想不出办法避免这种情况。一个命中或一个方向将不胜感激。我正在考虑以某种方式实现一个堆,以便它从堆中扣除查询 a 并创建一个最大堆以查看最大差异和 den xor。但这也需要 O(NQT)

【问题讨论】:

  • 为什么你的循环从 1 开始?为什么分配而不解除分配?为什么要在远离使用点的地方声明变量?你为什么using namespace std;?先清理代码,得到巨大的常数因子。
  • 清理了Itsy Bitsy Things。我的主要代码已全部清理。在我清理不必要的东西之前,这有点生硬。从 1 开始,因为最初没有得到结果,只是为了确保从 1 到 N 的所有内容,所以 dat 按照我认为的算法进行。
  • 可能更适合 codereview.stackexchange.com
  • @Yakk,我认为您对using namespace std; 有点苛刻,这不在标头中,因此对于大多数代码来说它是常见且完全可以接受的
  • 我相信这里也有人问过同样的问题。 stackoverflow.com/questions/9395549/…

标签: c++ algorithm encryption optimization c-preprocessor


【解决方案1】:

我不认为摆弄你写的东西会影响你的速度。你想要时间复杂度更高的东西。

从问题中,我假设他们想要每个查询 O(log N) 的东西。我最初的想法是segment tree,但我找不到使用它们来最大化a ^ x[i]的方法。

我相信您应该使用所有数字都小于2^15 的事实。另一件需要注意的是,您希望最大化 xor 操作。假设你有(二进制)

a = b_1 b_2 ... b_n

您要么拥有所有x[j]p &lt;= j &lt;= q 的最高有效位等于b_1,或者有一些x[j] 的最高有效位是b_1 的补码。这是因为b xor ~b = 1 代表b in {0,1}。您只选择那些 MSB 是b_1 补码的j,然后继续下一位(对应于b_2)。

问题是这种蛮力实现比你已经在做的更糟糕,但它可能会帮助你更快地实现。

【讨论】:

  • 只有在 x[j] 的 MSB 是 a 的补码的情况下才能进行 XOR 运算,这将减少数量。异或运算。但它不会也添加N个比较来决定其中哪些具有补充的MSB吗?这不会使时间复杂度与原来相同吗?
  • 是的,这就是我的方法失败的地方。我不知道如何完全解决您的问题,但我相信这与数字都相对较小(小于 2^15)有关。如果我想到更好的方法,我会编辑我的答案。
【解决方案2】:

一些提示:

  • cin 的所有调用都使得无法衡量此代码的性能。您应该提前从文件中读取所有数据。
  • 不要每次查看都分配x,使用malloc 分配一次,并在需要时调用realloc 使缓冲区更长。内存分配会减慢速度。

内部循环非常简单,因此编译器可以对其进行矢量化。通过查看反汇编确保这确实发生了。如果不是,请使用 SSE 内在函数一次处理 4 个或 8 个 8 个元素。

【讨论】:

    【解决方案3】:

    这是修改后的代码以及我在 cmets 中提出的建议。

    避免在性能敏感代码中使用 C++ iostream。 (FWIW,一般避免 iostreams) 尽可能避免分配/释放。在下面的代码中,vector::resize 将 注意向量始终至少具有所需的空间。 不是性能,而是可读性:使用空格和运算符。声明变量关闭 到他们使用的地方。

    #include <cstdio>
    #include <vector>
    #include <algorithm>
    
    int main() {
        int T;
        std::vector<int> x;
    
        std::scanf ("%d", &T);
        for (int k = 0; k < T ; ++k) {
    
            int N, Q;
            std::scanf ("%d%d", &N, &Q);
            x.resize (N);
    
            for (int i = 0; i < N; ++i)
                std::scanf ("%d", &x[i]);
    
            for (int i = 0; i < Q; ++i) {
                int a, p, q;
                std::scanf ("%d%d%d", &a, &p, &q);
    
                int pres = -999;
                for(int j = p - 1; j < q; ++j)
                    pres = std::max (pres, a ^ x[j]);
    
                std::printf ("%d\n", pres);
            }
        }
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-07-14
      • 1970-01-01
      • 2021-07-25
      • 2013-05-29
      • 2015-09-20
      • 1970-01-01
      • 2021-07-04
      相关资源
      最近更新 更多