Cod sursa(job #948600)

Utilizator mgntMarius B mgnt Data 11 mai 2013 10:37:51
Problema Abc2 Scor 0
Compilator cpp Status done
Runda Arhiva de probleme Marime 8.65 kb
// 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;
}