我正在做这个问题,称为在Hackerrank上的算术级数。如何加快这个C++代码(尤其是factorial和pow部分)
https://www.hackerrank.com/challenges/arithmetic-progressions
我的解决方案通过了所有的前六个测试。我已尽全力优化我的代码,包括缓存,更高效的操作。我仍然无法通过测试。我认为我失败的两个地方是因子函数和pow函数。
基本上,我用unordered_map来存储所有以前的结果。如果论证是关键之一,我会马上返回结果。
这里是我的代码:
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
#include <unordered_map>
#include <utility>
#include <ctime>
#include <sys/time.h>
using namespace std;
#define mod(m) (m > 1000003) ? m % 1000003 : m
//used for hashing the pair
namespace std {
template<typename a, typename b>
struct hash< pair<a, b> > {
private:
const hash<a> ah;
const hash<b> bh;
public:
hash() : ah(), bh() {};
size_t operator()(const std::pair<a, b> &p) const {
return ah(p.first)^bh(p.second);
}
};
} // namespaces
//the code below is used for collecting statistics
/*
typedef unsigned long long timestamp_t;
static timestamp_t get_timestamp()
{
struct timeval now;
gettimeofday (&now, NULL);
return now.tv_usec + (timestamp_t)now.tv_sec * 1000000;
}
*/
//note that the number could get really large, that's why I use unsigned long long for most of data type
static unsigned long long cache_D[100000];
static unsigned long long cache_d[100000];
static unsigned long long cache_p[100000];
static unordered_map<unsigned long long, unsigned long long> cache_F; //use unordered_map to store the factorial, avg insert, lookup O(1)
static unordered_map<pair<unsigned long long, unsigned long long>, unsigned long long> cache_P; //use unordered_map to store the pow
//static double pow_sec = 0;
//static double fac_sec = 0;
/**
* Use the fast pow algorithm. On top of that, I add caching (stored in unordered map) to speed up the pow
* @param x base
* @param y exponent
* @return x^y
*/
unsigned long long pow(unsigned long long x, unsigned long long y)
{
//timestamp_t t0 = get_timestamp();
pair<unsigned long long, unsigned long long> curr(x, y);
if(cache_P.find(curr) != cache_P.end())
{
//timestamp_t t1 = get_timestamp();
//pow_sec += (t1 - t0)/1000000.0L;
return cache_P[curr];
}
unsigned long long result = 1;
unsigned long long mod_x = mod(x);
//unsigned long long count = 0;
while(y)
{
if (y & 1)
{
unsigned long long temp = result * mod_x;
result = mod(temp);
}
y >>= 1;
unsigned long long temp = mod_x * mod_x;
mod_x = mod(temp);
}
cache_P[curr] = result;
//timestamp_t t1 = get_timestamp();
//pow_sec += (t1 - t0)/1000000.0L;
return result;
}
/**
* same idea as pow, caching whenever I can
* @param x number to be factorialized
* @return x!
*/
unsigned long long factorial(unsigned long long x)
{
//timestamp_t t0 = get_timestamp();
if (cache_F.find(x) != cache_F.end())
{
//timestamp_t t1 = get_timestamp();
//fac_sec += (t1 - t0)/1000000.0L;
return cache_F[x];
}
else
{
unsigned long long result = 1;
//here we go from x to 1 since we could speed up operation as soon as we have x - 1 or x - 2 or x - 3 in our caching (just x * (x - 1)!)
for(unsigned long long i = x; i >= 1; i--)
{
if(cache_F.find(i) != cache_F.end())
{
unsigned long long temp1 = result * cache_F[i];
result = mod(temp1);
cache_F[x] = result;
//timestamp_t t1 = get_timestamp();
//fac_sec += (t1 - t0)/1000000.0L;
return result;
}
unsigned long long mod_i = mod(i);
unsigned long long temp2 = result * mod_i;
result = mod(temp2);
}
cache_F[x] = result;
//timestamp_t t1 = get_timestamp();
//fac_sec += (t1 - t0)/1000000.0L;
return result;
}
}
void query(int from, int to)
{
unsigned long long k = 0;
unsigned long long constant = 1;
for(int i = from - 1; i < to; i++)
{
k += cache_p[i];
unsigned long long temp = constant * cache_D[i];
constant = mod(temp);
}
unsigned long long temp = constant * factorial(k);
constant = mod(temp);
printf("%llu %llu\n", k, constant);
}
void update(int from, int to, int how_much)
{
for(int i = from - 1; i < to; i++)
{
cache_p[i] += how_much;
unsigned long long temp = cache_D[i] * pow(cache_d[i], (unsigned long long)how_much);
cache_D[i] = mod(temp);
}
}
int main() {
int num_vec, num_operations;
FILE *pFile = fopen("input.txt", "r");
fscanf(pFile, "%d", &num_vec);
for(int i = 0; i < num_vec; i++)
{
unsigned long long a, d, q;
fscanf(pFile, "%llu %llu %llu", &a, &d, &q);
cache_d[i] = d;
cache_p[i] = q;
cache_D[i] = pow(d, q);
}
fscanf(pFile, "%d", &num_operations);
for(int i = 0; i < num_operations; i++)
{
int what_operation, from, to;
fscanf(pFile, "%d %d %d", &what_operation, &from, &to);
if(what_operation == 0)
{
query(from, to);
}
else if (what_operation == 1)
{
int add_q;
fscanf(pFile, "%d", &add_q);
update(from, to, add_q);
}
}
printf("sec for pow: %f\n sec for fac: %f", pow_sec, fac_sec);
return 0;
}
如果有谁知道如何进一步优化我的代码,这将是很有益的。谢谢!
你有什么资料?它在哪里比较慢? –
那么I/O操作呢?也许你应该用'fread'而不是'fscanf'来读取文件。并在读取文件后处理数据。 –
也许这个问题应该更好地去codereview – PlasmaHH