我正在尝试解决SPOJ问题SUMFOUR ....我正在测试案例9 http://www.spoj.com/problems/SUMFOUR/
那么,我的代码的哪一部分需要编辑以及如何编辑?这里N< = 4000
#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;
}
答案 0 :(得分:2)
问题在于:
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,因为find
和count
时间复杂度为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之后,事实证明地图不够快,所以我对二进制搜索进行了更改,并被接受了。
答案 1 :(得分:0)
请不要使用Map作为最坏的案例复杂性可以是O(log(n))。
反过来你可以只使用两个排序的数组和
中的每个元素第一个数组,Binary在第二个累积数组中搜索其-ve代理。
只需将最后一行中的find方法更改为二进制搜索(c.begin(),c.end(),key),然后查找重复项,直到该索引结束,因为它给出了lower_bound索引。
总和给出了答案,其预期的复杂性是
为O(n ^ 2log(N))。