Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- Author: Pablo Moreno Olalla
- Email address: darthbrevu@yahoo.es
- */
- #include <map>
- #include <set>
- #include <list>
- #include <cmath>
- #include <cstdio>
- #include <string>
- #include <numeric>
- #include <sstream>
- #include <utility>
- #include <iostream>
- using namespace std;
- //I've REALLY looked for efficiency on this one, although I feel that "addRangeDataSym" could have been better on that respect.
- bool isPrime(unsigned long long ull) {
- unsigned long long sq=static_cast<unsigned long long>(ceil(sqrt(static_cast<long double>(ull))));
- for (unsigned long long i=3;i<=sq;++i) if (ull%i==0) return false;
- return true;
- }
- inline unsigned long long reverse(unsigned long long ull) {
- unsigned long long res=0;
- while (ull) {
- res*=10;
- res+=ull%10;
- ull/=10;
- };
- return res;
- }
- class EmirpRange {
- public:
- char first;
- char last;
- char total;
- inline EmirpRange(unsigned long long f,unsigned long long l,unsigned long long t):first(static_cast<char>(f)),last(static_cast<char>(l)),total(static_cast<char>(t)) {}
- inline bool operator<(const EmirpRange &er) const {
- if (total<er.total) return true;
- else if (er.total<total) return false;
- else if (first<er.first) return true;
- else if (er.first<first) return false;
- else return last<er.last;
- }
- };
- //An object of this kind will be used so that calculations are not repeated. In this kind of problems, we
- //need speed! Otherwise it would take TOO long to calculate a large enough string of numbers.
- typedef map<EmirpRange,pair<set<unsigned long long>,unsigned long long> > EmirpMap;
- inline unsigned long long numberOfDigits(unsigned long long ull,unsigned long long &first) {
- unsigned long long res=0;
- while (ull) {
- if (ull<10) first=ull;
- ull/=10;
- ++res;
- }
- return res;
- }
- typedef list<pair<EmirpRange,bool> > RangeList;
- inline void generateEmirpRange(unsigned long long ull,RangeList &out) {
- static unsigned long long emirpable[]={1,3,7,9};
- unsigned long long firstDigit;
- unsigned long long digits=numberOfDigits(ull,firstDigit);
- size_t maxSearch=0;
- for (size_t i=1;i<4;++i) if (emirpable[i]<=firstDigit) ++maxSearch;
- else break;
- if (digits<2) return;
- for (unsigned long long i=2;i<digits;++i) for (size_t a=0;a<4;++a) for (size_t b=0;b<4;++b) out.push_back(make_pair(EmirpRange(emirpable[a],emirpable[b],i),true));
- for (size_t a=0;a<maxSearch;++a) for (size_t b=0;b<4;++b) out.push_back(make_pair(EmirpRange(emirpable[a],emirpable[b],digits),true));
- for (size_t b=0;b<4;++b) out.push_back(make_pair(EmirpRange(emirpable[maxSearch],emirpable[b],digits),false));
- }
- inline unsigned long long power10(unsigned long long exp) {
- unsigned long long res=1;
- //I could have used floating arithmetic, but I don't like its small lack of precision.
- while (exp>0) {
- res*=10;
- --exp;
- }
- return res;
- }
- void addRangeDataSym(EmirpMap &data,const EmirpRange& er) {
- set<unsigned long long> &sNorm=data[er].first;
- unsigned long long n=static_cast<unsigned long long>(er.last)+power10(static_cast<unsigned long long>(er.total-1))*static_cast<unsigned long long>(er.first);
- unsigned long long maxData=power10(static_cast<unsigned long long>(er.total-2));
- unsigned long long r;
- for (size_t i=0;i<maxData;++i) {
- r=reverse(n);
- if (n!=r) {
- if (isPrime(n)&&isPrime(r)) {
- sNorm.insert(n);
- sNorm.insert(r);
- }
- }
- n+=10;
- }
- data[er].second=accumulate(sNorm.begin(),sNorm.end(),0);
- }
- void addRangeData(EmirpMap &data,const EmirpRange &er) {
- if (er.first==er.last) {
- addRangeDataSym(data,er);
- return;
- }
- EmirpRange revEr=er;
- swap(revEr.first,revEr.last);
- set<unsigned long long> &sNorm=data[er].first;
- set<unsigned long long> &sRev=data[revEr].first;
- unsigned long long n=static_cast<unsigned long long>(er.last)+power10(static_cast<unsigned long long>(er.total-1))*static_cast<unsigned long long>(er.first);
- unsigned long long maxData=power10(static_cast<unsigned long long>(er.total-2));
- unsigned long long r;
- for (size_t i=0;i<maxData;++i) {
- if (isPrime(n)) {
- r=reverse(n);
- if (isPrime(r)) {
- sNorm.insert(n);
- sRev.insert(r);
- }
- }
- n+=10;
- }
- data[er].second=accumulate(sNorm.begin(),sNorm.end(),0);
- data[revEr].second=accumulate(sRev.begin(),sRev.end(),0);
- }
- unsigned long long sumEmirpsUpTo(unsigned long long in,EmirpMap &data) {
- RangeList ranges;
- generateEmirpRange(in,ranges);
- unsigned long long res=0;
- for (RangeList::const_iterator it=ranges.begin();it!=ranges.end();++it) {
- if (data.count(it->first)==0) addRangeData(data,it->first);
- if (it->second) res+=data[it->first].second;
- else {
- set<unsigned long long> &container=data[it->first].first;
- res+=accumulate(container.begin(),container.upper_bound(in),0);
- }
- }
- return res;
- }
- int main(int argc,char **argv) {
- //The first two lines are not strictly necessary, but make the code a little more handy.
- if (argc>=2) freopen(argv[1],"r",stdin);
- if (argc>=3) freopen(argv[2],"w",stdout);
- string tmp;
- unsigned long long ull;
- EmirpMap data;
- do {
- getline(cin,tmp);
- istringstream iss(tmp);
- iss>>ull;
- if (!iss.fail()) cout<<sumEmirpsUpTo(ull,data)<<endl;
- } while (!cin.eof());
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement