Pagini recente » Cod sursa (job #1220122) | Cod sursa (job #3271270) | Cod sursa (job #405421) | Cod sursa (job #2735793) | Cod sursa (job #948600)
Cod sursa(job #948600)
// http://infoarena.ro/problema/abc2
//
// Folosesc abordarea descrisă în comentarii.
// Asociez secvențele de lungimea cuvintelor, numere în baza 3.
//
// 3**20 = 3486784401 < 4294967296 = 2**32
// → un int unsigned, pe 32 de biți poate reprezenta numerele
// (20 e lungimea maximă a cuvintelor)
// .
//
#include <cstddef>
#include <stdexcept>
#include <string>
#include <iostream>
#include <fstream>
#include <set>
// cstring declares ::std::strlen
#include <cstring>
namespace abc2
{
size_t const maxn = 50000;
size_t const maxc = 20;
size_t const maxc2 = 2+maxc;
size_t const maxv = (maxn*maxc);
size_t const maxv2 = (2+maxv);
size_t const maxm = 10000000;
size_t const maxm2 = (2+maxm);
typedef int unsigned uint32; // may be more than 32
/// \brief All the data used to solve the problem.
/// The input and extra space used for computing the output.
struct abc2_data
{ /// \brief Space to store the ancient text.
char m_text_symbols[maxm2];
/// \brief The length of the ancient text.
size_t m_text_size;
/// \brief Space to store all the words in the Makako language
/// , one word after the other, with no separator.
char m_words_symbols[maxv2];
/// The number of words in the Makako language.
::std::size_t m_number_of_words;
/// The length of each word in the Makako language.
::std::size_t m_word_size;
/// \brief The set of numbers associated with words.
::std::set<uint32> m_words;
/// \brief Number of occurrences;
::std::size_t m_number_of_occurrences;
} // struct abc2_state
;
// ______________________________________________________________________________
/// \brief Constructs the set of numbers associated to words.
class words_processing
{ private:
abc2_data & m_data;
public:
words_processing
( abc2_data & data
)
throw()
: m_data(data)
{ build();
}
private:
void
build
()
throw()
{ this->initialize_with_no_words();
this->add_words();
}
void
initialize_with_no_words
()
throw()
;
void
add_words
()
throw()
;
} // class words_processing
;
void
words_processing::initialize_with_no_words
()
throw()
{ ::std::set<uint32> tmp; // the empty set
abc2_data & d = this->m_data;
::std::set<uint32> & words = d.m_words;
// no-throw, no-fail
tmp.swap(words);
}
void
words_processing::add_words
()
throw()
{ // The result:
::std::set<uint32> tmp;
// Interation for all words:
size_t i;
abc2_data & d = this->m_data;
size_t const z = d.m_number_of_words;
size_t const n = d.m_word_size;
char * pattern = d.m_words_symbols; // the current word
// Iteration for a word:
size_t j;
uint32 sum;
uint32 digit;
char symbol;
for(i=0; z>i; ++i)
{ // Add the number for (1+i)-th word, into the set.
sum = 0;
for(j=0; n>j; ++j)
{ symbol = pattern[j]; // is one of 'a', 'b', or 'c'
symbol = (symbol - 'a');
digit = (static_cast<uint32>(symbol) );
sum = ((3*sum) + digit);
}
tmp.insert(sum);
// Update position of the current word.
pattern += n;
}
// no-throw, no-fail
::std::set<uint32> & words = d.m_words;
tmp.swap(words);
}
// ______________________________________________________________________________
/// \brief Solves the abc2 problem.
class solver
{ private:
abc2_data & m_data;
public:
solver
( abc2_data & data
)
: m_data(data)
{ this->process_words();
this->count_number_of_occurrences();
}
private:
void
process_words
()
;
void
count_number_of_occurrences
()
throw()
;
} // class solver
;
void
solver::process_words
()
{ // Construct the finite automaton.
words_processing numbers_for_words_processing(m_data);
// The constructor of numbers_for_words_processing needs
// to be evaluated
// , because its evaluation contains side effects:
// it changes the state of the m_data object
// .
(void) numbers_for_words_processing;
}
void
solver::count_number_of_occurrences
()
throw()
{ // Count occurrences, using the set with numbers for words.
size_t i;
abc2_data & d = m_data;
char * q = d.m_text_symbols;
size_t m = d.m_text_size;
size_t const n = d.m_word_size;
size_t h = 0; // The number of occurrences.
::std::set<uint32> & words = d.m_words;
uint32 msd = 1; // To remove most significant digit.
char symbol;
uint32 sum = 0;
uint32 digit;
bool match;
for(i=1; n>i; ++i) { msd = (3*msd); }
for(i=0; ((m>i) && (n>i)); ++i)
{ symbol = q[i]; // one of 'a', 'b', or 'c'
symbol = (symbol - 'a');
digit = (static_cast<uint32>(symbol) );
sum = ( (3*sum) + digit);
}
if(n == i)
{ match = ( (words.end() ) != (words.find(sum) ) );
if(match)
{ ++h; }
}
for( ; m>i; ++i)
{ symbol = q[i]; // one of 'a', 'b', or 'c'
symbol = (symbol - 'a');
digit = (static_cast<uint32>(symbol) );
sum = (sum % msd);
sum = ( (3*sum) + digit);
match = ( (words.end() ) != (words.find(sum) ) );
if(match)
{ ++h; }
}
// no-throw, no-fail
::std::size_t & ans =
d.m_number_of_occurrences;
ans = h;
}
// ______________________________________________________________________________
/// \brief Reads input.
class input_reader
{ private:
/// \brief The abc2 data.
abc2_data & m_data;
/// \brief Input is not valid.
///
/// This data member is initialized
/// , only when processing is not successful.
bool m_input_is_not_valid;
/// \brief Input error occurred.
///
/// This data member is initialized
/// , only when processing is not successful.
bool m_io_error_occurred;
/// \brief Processing is successful.
bool m_ok;
public:
input_reader
( abc2_data & data
, bool & ok
)
: m_data(data)
, m_ok(read_input() )
{ ok = m_ok;
}
private:
bool
read_input
()
throw()
;
bool
read_the_ancient_text
( ::std::istream & is
)
throw()
;
bool
read_all_the_words_in_the_makako_language
( ::std::istream & is
)
throw()
;
} // class input reader.
;
bool
input_reader::read_input
()
throw()
{ bool ok;
::std::ifstream is("abc2.in");
ok = is.good();
if( !ok)
{ m_io_error_occurred = true;
return false;
}
abc2_data & d = this->m_data;
char * q = d.m_text_symbols;
::std::size_t & m = d.m_text_size;
char * p = d.m_words_symbols;
::std::size_t & n = d.m_word_size;
::std::size_t & z = d.m_number_of_words;
::std::size_t i = 0;
is >> q;
m = ::std::strlen(q);
is >> p;
n = ::std::strlen(p);
++ i; p += n;
while(is >> p)
{ ++i; p += n;
}
z = i;
return true; // Success.
}
// ______________________________________________________________________________
/// \brief Writes output.
class output_writer
{ private:
/// \brief The abc2 data.
abc2_data & m_data;
/// \brief Processing was successful.
bool m_ok;
public:
output_writer
( abc2_data & data
, bool & ok
)
: m_data(data)
, m_ok(write_output() )
{ ok = m_ok;
}
private:
bool
write_output
()
throw()
;
} // class output_writer
;
bool
output_writer::write_output
()
throw()
{ bool ok;
::std::ofstream os("abc2.out");
ok = os.good();
if( !ok)
{ return false; } // Failure.
abc2_data & d = this->m_data;
size_t const & number_of_occurrences =
d.m_number_of_occurrences;
os << number_of_occurrences << ::std::endl;
ok = os.good();
if( !ok)
{ return false; } // Failure.
return true; // Success.
}
} // namespace abc2
/// The spaces used by the program.
static
::abc2::abc2_data
s_data;
/// Because the abc2_data is plain old data
/// , so its construction is guaranteed
/// not to throw a c++ exception.
bool
solve_the_abc2_problem
()
{ ::abc2::abc2_data & d = s_data;
bool ok;
::abc2::input_reader r(d, ok);
if( !ok)
{ return false; } // Failure. No input.
(void) r;
::abc2::solver s(d);
(void) s;
::abc2::output_writer w(d, ok);
if( !ok)
{ return false; } // Failure. No output.
return true; // Success.
}
int
main
()
{ int status;
try
{ bool ok = solve_the_abc2_problem();
status = ( ok ? 0 : 1 );
}
catch ( ... )
{ status = 2;
}
return status;
}