Cod sursa(job #948591)

Utilizator mgntMarius B mgnt Data 11 mai 2013 10:13:39
Problema Abc2 Scor 0
Compilator cpp Status done
Runda Arhiva de probleme Marime 14.83 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>

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;
}

// ______________________________________________________________________________

class string_is_an_abc_string
{ private:
  /// \brief  The string.
  char  * m_p;
  /// \brief  The length of the string.
  size_t  m_k;
  /// \brief  Is an abc string.
  bool    m_is_an_abc_string;
  
  public:
  
  string_is_an_abc_string
  ( char    * p
  , size_t    k
  )
  : m_p(p)
  , m_k(k)
  , m_is_an_abc_string(is_an_abc_string() )
  {}
  
  private:
  
  bool
  is_an_abc_string
  ()
  const
  throw()
  ;
  
  public:
  
  operator
  bool
  ()
  throw()
  { return m_is_an_abc_string; }
  
} // class string_is_an_abc_string
;

bool
string_is_an_abc_string::is_an_abc_string
()
const
throw()
{ char    * p = m_p;
  size_t    k = m_k;
  
  size_t    i;
  char      c;
  bool      ok;
  for(i=0; k>i; ++i)
  { c = p[i];
    ok = (     ('a' == c)
            || ('b' == c)
            || ('c' == c)
         )
         ;
    if( !ok)
    { return false; } // It is not an abc string.
  }
  
  return true; // It is an abc string.
}

// ______________________________________________________________________________

class makako_language_reader
{ private:
  /// \brief  Reference to the input stream.
  ::std::istream  & m_is;
  /// \brief  Reference to the abc2 data.
  abc2_data       & m_data;
  /// \brief  Reference to the input is not valid variable.
  bool            & m_input_is_not_valid;
  /// \brief  Reference to the io-error-occurred variable.
  bool            & m_io_error_occurred;
  /// \brief  Processing was successful.
  bool              m_ok;
  
  public:
  
  makako_language_reader
  ( ::std::istream  & is
  , abc2_data       & data
  , bool            & input_is_not_valid
  , bool            & io_error_occurred
  , bool            & ok
  )
  throw()
  ;
  
  private:
  
  bool
  read_the_makako_language
  ()
  throw()
  ;
  
  bool
  read_word
  ( char    * p
  , size_t  & k
  )
  throw()
  ;
  
  bool
  read_the_last_line
  ()
  throw()
  ;
  
} // class makako_language_reader
;

makako_language_reader::makako_language_reader
( ::std::istream  & is
, abc2_data       & data
, bool            & input_is_not_valid
, bool            & io_error_occurred
, bool            & ok
)
throw()
: m_is(is)
, m_data(data)
, m_input_is_not_valid(input_is_not_valid)
, m_io_error_occurred(io_error_occurred)
, m_ok(read_the_makako_language() )
{ ok = m_ok;
}

bool
makako_language_reader::read_the_makako_language
()
throw()
{ bool  ok;
  
  abc2_data  & d   = this->m_data;
  char       * p   = d.m_words_symbols;
  size_t       len;
  
  // Read first word.
  
  ok = this->read_word(p, len);
  if( !ok)
  { return false; } // Failure.
  
  bool    const first_is_empty = (0>=len);
  // Read remaining words.
  
  
  size_t  const len0 = len;
  size_t        i    = 1;
  while((maxn > i) && (0<len))
  { p += len0;
    ok = this->read_word(p, len);
    if( !ok)
    { return false; } // Failure.
    
    ok = ((len0 == len) || (0 == len));
    if( !ok)
    { return false; }
    
    ++i;
  }
  
  // Read last line.
  
  if(0 != len)
  { ok = read_the_last_line();
    if( !ok)
    { return false; } // Failure.
  }
  else
  { if(false == first_is_empty)
    { --i; }
  }
  
  // no-throw, no-fail
  ::std::size_t  & number_of_words =
    d.m_number_of_words;
  ::std::size_t  & word_size =
    d.m_word_size;
  number_of_words = i;
  word_size       = len0;
  
  return true; // Success.
}

bool
makako_language_reader::read_word
( char    * p
, size_t  & k
)
throw()
{ ::std::istream  & is = this->m_is;
  
  bool  ok;
  bool  withSeparator = true;
  
  is.getline(p, maxc2);
  ok = is.good();
  if( !ok)
  { ok = is.eof();
    if( !ok)
    { m_io_error_occurred = true;
      return false; // Failure.
    }
    withSeparator = false;
  }
  
  // Compute len, line lenth.
  ::std::streamsize  tmp = is.gcount();
  if(0 > tmp)
  { m_io_error_occurred = true;
    return false; // Failure.
  }
  
  if(0 < tmp)
  { if(withSeparator)
    { --tmp; }
  }
  
  size_t  len = static_cast<size_t>(tmp);
  p[len] = '\0'; // Only for "(gdb) print p".
  ok = (len<=maxc);
  if( !ok)
  { m_input_is_not_valid = true;
    return false; // Failure.
  }
  
  ok = string_is_an_abc_string(p, len);
  if( !ok)
  { m_input_is_not_valid = true;
    return false; // Failure.
  }
  
  // no-throw, no-fail
  k = len;
  return true; // Success.
}

bool
makako_language_reader::read_the_last_line
()
throw()
{ ::std::istream  & is = m_is;
  bool              ok;
  bool              withSeparator = true;
  
  // Read line, into variable space.
  
  char  space[2];
  
  is.getline(space, 2);
  
  ok = is.good();
  if( !ok)
  { ok = is.eof();
    if( !ok)
    { m_io_error_occurred = true;
      return false; // Failure.
    }
    withSeparator = false;
  }
  
  // Compute line length, into variable len.
  
  ::std::streamsize  tmp = is.gcount();
  
  if(0 > tmp)
  { m_io_error_occurred = true;
    return false; // Failure.
  }
  
  if(0 < tmp)
  { if(withSeparator)
    { --tmp; }
  }
  
  ::std::size_t  len = static_cast< ::std::size_t>(tmp);
  space[len] = '\0'; // Only for "(gdb) print space".
  
  ok = (0 == len);
  if( !ok)
  { m_input_is_not_valid = true;
    return true; // Failure.
  }
  
  return true; // Success.
}


// ______________________________________________________________________________

/// \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;
  }
  
  ok = this->read_the_ancient_text(is);
  if( !ok)
  { return false; } // Failure.
  
  ok = this->read_all_the_words_in_the_makako_language(is);
  if( !ok)
  { return false; } // Failure.
  
  return true; // Success.
}

bool
input_reader::read_the_ancient_text
( ::std::istream  & is
)
throw()
{ abc2_data  & d = this->m_data;
  char       * p = d.m_text_symbols;
  // Read line.
  
  bool  withSeparator = true;
  
  is.getline(p, maxm2);
  bool  ok = is.good();
  if( !ok)
  { ok = is.eof();
    if( !ok)
    { m_io_error_occurred = true;
      return false; // Failure.
    }
    withSeparator = false;
  }
  
  // Compute line length.
  
  ::std::streamsize  tmp = is.gcount();
  if(0 > tmp)
  { m_io_error_occurred = true;
    return false; // Failure.
  }
  
  if(0 < tmp)
  { if(withSeparator)
    { --tmp; }
  }
  
  ::std::size_t  len =
    static_cast< ::std::size_t>(tmp);
  p[len] = '\0';
  ok = (len <= maxm);
  if( !ok)
  { m_input_is_not_valid = true;
    return false; // Failure.
  }
  
  ok = string_is_an_abc_string(p, len);
  if( !ok)
  { m_input_is_not_valid = true;
    return false; // Failure.
  }
  
  ::std::size_t  & text_size =
    d.m_text_size;
  
  // no-throw, no-fail
  text_size = len;
  
  return true; // Success.
}

bool
input_reader::read_all_the_words_in_the_makako_language
( ::std::istream  & is
)
throw()
{ bool  ok;
  makako_language_reader
    reader
      ( is
      , m_data
      , m_input_is_not_valid
      , m_io_error_occurred
      , ok
      )
      ;
  
  if( !ok)
  { return false; } // Failure.
  
  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;
}