【问题标题】:SPOJ SUMFOUR.....TLE on test case 9SPOJ SUMFOUR .....TLE 在测试用例 9
【发布时间】:2015-08-20 03:16:07
【问题描述】:

我正在尝试解决 SPOJ 问题 SUMFOUR....我在测试用例 9 http://www.spoj.com/problems/SUMFOUR/ 上获得 TLE

那么,我的代码的哪一部分必须编辑以及如何编辑?这里 N

#include <iostream>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<map>
#include<vector>

using namespace std;


int main()
{
int a[4005][5],n;
cin>>n;
for(int i=1;i<=n;i++)
    for(int j=1;j<=4;j++)
        scanf("%d",&a[i][j]);
int k=0;
for(int i=1;i<=n;i++)
{   int p=a[i][1];
    for(int j=1;j<=n;j++)
    {   b.push_back(p+a[j][2]);
        k++;
    }
}
k=0;
for(int i=1;i<=n;i++)
{   int p=a[i][3];
    for(int j=1;j<=n;j++)
    {   c.push_back(p+a[j][4]);
        k++;
    }
}
sort(b.begin(),b.end());
int cnt=0;
for(int j=0;j<k;j++)
    if(find(b.begin(),b.end(),-c[j])!=b.end() )
        cnt=cnt+count(b.begin(),b.end(),-c[j]) ;


printf("%d\n",cnt);
return 0;
}

【问题讨论】:

  • 如果您使用 C++ 编写代码,请使用从 0 到 n - 1 的 C++ 样式索引作为向量。 for(int i=1;i&lt;=n;i++) 看起来很尴尬。
  • 1) 请一致地缩进代码以提高可读性。建议在每个左大括号 '{' 后留 4 个空格,并在每个右大括号 '}' 之前取消缩进。注意由于不同的环境有不同的制表位/宽度,从不使用制表符进行缩进。 2)使用空行来偏移代码块以提高可读性。 3) 当请求用户输入时 (cin >> n) 总是以 cout
  • 1) 为什么要混合使用 'cin' 和 'scanf()' ? 2) 你真的希望用户输入多达 16000 个整数值吗? 3) 始终检查 scanf() 的返回值,而不是参数值,以确保操作成功。
  • 因为这是 C++,不应该像这样定义数组:'std::vector myvector (n);'而不是'int myvector[n]'?

标签: c++ c algorithm c++11 maps


【解决方案1】:

问题出在这里:

 for(int j=0;j<k;j++)
       if(find(b.begin(),b.end(),-c[j])!=b.end() )
           cnt=cnt+count(b.begin(),b.end(),-c[j]) ;

对于 n = 4000,所以 b 和 c 中有 4000^2 个元素。所以,这个循环的时间复杂度是 4000^4,findcount 时间复杂度是 O(n),这当然会导致你超出时间限制。

那么,如何减少时间呢?您可以使用 二分搜索 来加快计数过程,从而将上述循环的时间复杂度降低到 O(n^2 log n),因为我注意到您已经排序b.

或者,您可以使用map来统计并存储b和c中每个元素的频率。

map<long long, int> b;
map<long long, int> c;

for(int i=1;i<=n;i++)
{   long long p=a[i][1];
    for(int j=1;j<=n;j++)
    {   
        long long tmp =p + a[j][2];
        b[tmp] = b[tmp] + 1; 
    }
}
// Similar for c
map <long long, int>::iterator it;
long long result;
for (it = c.begin(); it != c.end(); ++it)
        result += c[it->first]*b[-(it->first)];

对于您的新更新,请更改此内容:

    for(int j=1;j<=n;j++)
    {   if( b.count(a[i][1]+a[j][2]) )
        {   b[a[i][1]+a[j][2]]+=1;
            c[a[i][3]+a[j][4]]+=1;
        }
        else
        {   b[a[i][1]+a[j][2]]=1;
            c[a[i][3]+a[j][4]]=1;
        } 
    }

进入这个:

    for(int j=1;j<=n;j++)
    {   
           b[a[i][1]+a[j][2]]+=1;
           c[a[i][3]+a[j][4]]+=1;            
    }

条件检查if( b.count(a[i][1]+a[j][2]) ) 仅用于b,而您将其用于c,这会使c 不正确。

更新:在尝试被SPOJ接受后,发现map不够快,所以我改成二分查找,被接受了。

我的accepted code

【讨论】:

【解决方案2】:

请不要使用 Map 作为其最坏情况复杂度可能是 O(log(n))。

因此,您可以只使用两个排序数组,并为每个元素使用

第一个数组,在第二个累积数组中二分查找它的 -ve 代理。

只需将 Last lines 中的 find 方法更改为 Binary search(c.begin(),c.end(),key) 并找到具有该索引的 repittons 直到结束,因为它给出了 lower_bound index 。

总和给出了答案,其预期的复杂性是

O(n^2log(n))。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-13
    • 2020-08-29
    相关资源
    最近更新 更多