I was solving a CodeForces problem, and kept getting Time Limit Exceeded, so as usual in these cases, I decided to try to migrate my code from Python to C++ in order to go faster. I noticed that my C++ implementation goes slower than my Python code.
The code dynamically updates a dictionary (in Python) or a map<long,long>
in C++. The only thing I see to explain that my C++ code is twice as slow as my Python 2 code is that a C++ map<long,long>
would be slower to access/insert than a Python dictionary, so I tried to change them into unordered_map
, to no avail.
The code runs with this example input instantaneously in Python, but takes more than 10 seconds in the C++ implementation. I see no reason for this code (that contains at most a few thousands simple operations) to last this long:
25
14 17 5 42 2 53 61 61 65 56 42 64 10 8 56 38 50 36 7 46 42 46 13 43 11
So my main question is: Which data structure should I use instead of unordered_map
to make this code as efficient as possible?
The only reason that I see for my code to be so inefficient would be that the implementation of find()
in an unordered_map
is incredibly slower, so I guess I'm not using the right structure to mimic the performance of Python's dictionary.
Of course, if you have any other remark on how I use C++, I will welcome your insights.
The problem if it interests you
C++ code (extremely slow):
#include <unordered_map>
#include <iostream>
#define REP(I, N) for (int I = 0; I < (N); ++I)
#define RI(X) scanf("%d", &(X))
#define Fi first
#define Sn second
typedef long long LL;
using namespace std;
bool isin(long s, unordered_map<long,long> m){
return (m.find(s)!=m.end());
}
long deuxpownmodprime(long n,long mod){
n=(n%(mod-1));
long res;
res = 1;
if (n&1){res=2;}
if (n<=1) {return res;}
long ps2=deuxpownmodprime(n/2,mod);
long long resll;
resll=res;
resll*=ps2;
resll*=ps2;
return (resll%mod);
}
int main(){
long totf=0;
int n;
RI(n);
int decomps[71]={0, 0, 1, 2, 0, 4, 3, 8, 1, 0, 5, 16, 2, 32, 9, 6, 0, 64, 1, 128, 4, 10, 17, 256, 3, 0, 33, 2, 8, 512, 7, 1024, 1, 18, 65, 12, 0, 2048, 129, 34, 5, 4096, 11, 8192, 16, 4, 257, 16384, 2, 0, 1, 66, 32, 32768, 3, 20, 9, 130, 513, 65536, 6, 131072, 1025, 8, 0, 36, 19, 262144, 64, 258, 13};
long mod= 1000000000+7;
unordered_map<long,long> ot;
long nbm=(1<<19);
// long tot[nbm]={0};
ot.insert(pair<long,long> (0,1));
int dn[71]={0};
REP(i,n){
int a;
RI(a);
dn[a]++;
}
REP(i,71)
{
if (dn[i]>0){
totf+=dn[i]-1;
int a=decomps[i];
unordered_map<long,long> ta;
for (auto it : ot){
long m=(it.Fi)^a;
bool j=isin(m,ta);
if (!j){
ta.insert(pair<long,long> (m,it.Sn));
}
else{
ta[m]+=it.Sn;
//ot[it.Fi]=ot[m];
}
}
for (auto it: ta)
{
if (!isin(it.Fi,ot)){
ot[it.Fi]=it.Sn;
}
else{
ot[it.Fi]+=it.Sn;
}
}
}
}
long long c=ot[0];
c*=deuxpownmodprime(totf,mod);
cout<<(c-1)%mod<<endl;
}
Python code that does the exact same thing but working faster:
n=[int(k) for k in raw_input().split(" ")][0]
a=[int(kk) for kk in raw_input().split(" ")]
mod= 1000000000+7;
global pows2
pows2={}
def p2(n):
if n<=1:
return 2**n
if n in pows2:
return pows2[n]
res=2**(n%2)
p2m=p2(n/2)
res=((res*p2m*p2m)%mod)
pows2[n]=res
return res
decomps=[0, 0, 1, 2, 0, 4, 3, 8, 1, 0, 5, 16, 2, 32, 9, 6, 0, 64, 1, 128, 4, 10, 17, 256, 3, 0, 33, 2, 8, 512, 7, 1024, 1, 18, 65, 12, 0, 2048, 129, 34, 5, 4096, 11, 8192, 16, 4, 257, 16384, 2, 0, 1, 66, 32, 32768, 3, 20, 9, 130, 513, 65536, 6, 131072, 1025, 8, 0, 36, 19, 262144, 64, 258, 13]
p219=524288;
ot={0:1}
dn=[0]*71
for k in range(n):
dn[a[k]]+=1
totp=0
for i in range(1,71):
if dn[i]>0:
aa=decomps[i]
totp+=dn[i]-1
ta={}
for k in ot.keys():
m=k^aa
ta[m]=ot[k]
for k in ta.keys():
if k not in ot:
ot[k]=0
ot[k]+=ta[k]
print (ot[0]*p2(totp)-1)%mod
isin()
function makes a copy of theunordered_set
every single time it's called. \$\endgroup\$bool isin(long s, unordered_map<long,long> m)
. Here you are making a copy of the map each time you callisin
!!!! \$\endgroup\$