Friday, September 30, 2016

UVa 702 - The Vindictive Coach

Accepted date: 2016-09-30
Run Time: 0.000
Ranking (as of 2016-09-30): 129 out of 530
Language: C++

/*
  UVa 702 - The Vindictive Coach

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_702_The_Vindictive_Coach.cpp
*/

#include <cstdio>

const int N_max = 22;
long long nr_alignments[N_max][N_max][N_max];
  // nr_alignments[i][j][k] is the number of alignments at the i-th player 
  // with j players less than i-th player' number and 
  // k players greater than -i-th player's number

int main()
{
  int N, m;
  while (scanf("%d %d", &N, &m) != EOF) {
    if (N == 1) {
      puts("1");
      continue;
    }
    for (int i = 0; i < N; i++)
      for (int j = 0; j < N; j++)
        for (int k = 0; k < N; k++)
          nr_alignments[i][j][k] = 0;
    int n = 0, less;
    if (m == 1) {
      n++;
      if (N > 2)
        nr_alignments[n][1][N - 3] = 1;
      else
        nr_alignments[n][0][0] = 1;
    }
    else
      nr_alignments[n][m - 1][N - m] = 1;
    for (n++, less = 1; n < N; n++, less = 1 - less) {
      for (int i = 0; i < N; i++)
        for (int j = 0; j < N; j++) {
          long long nr = nr_alignments[n - 1][i][j];
          if (nr) {
            if (less && i) {
              for (int ii = i - 1, jj = j; ii >= 0; ii--, jj++)
                nr_alignments[n][ii][jj] += nr;
            }
            else if (!less && j) {
              for (int ii = i, jj = j - 1; jj >= 0; ii++, jj--)
                nr_alignments[n][ii][jj] += nr;
            }
          }
        }
#ifdef DEBUG
      printf("%d\n  ", n);
      for (int i = 0; i < N; i++)
        for (int j = 0; j < N; j++) {
          long long nr = nr_alignments[n][i][j];
          if (nr)
            printf("[%d][%d]:%lld ", i, j, nr);
        }
      putchar('\n');
#endif
    }
    long long nr = 0;
    for (int i = 0; i < N; i++)
      for (int j = 0; j < N; j++)
        nr += nr_alignments[N - 1][i][j];
    printf("%lld\n", nr);
  }
  return 0;
}

Tuesday, September 27, 2016

UVa 12124 - Assemble

Accepted date: 2016-09-27
Run Time: 0.080
Ranking (as of 2016-09-27): 321 out of 391
Language: C++

Sort of dynamic programming, although very slow.


/*
  UVa 12124 - Assemble

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_12124_Assemble.cpp
*/

#include <algorithm>
#include <string>
#include <vector>
#include <map>
#include <cstdio>
using namespace std;

const int n_max = 1000, nr_chars_max = 20;

#ifdef DEBUG
void print_qualities(const map<int, int>& qualities)
{
  printf("%d\n  ", qualities.size());
  for (map<int, int>::const_iterator i = qualities.begin(); i != qualities.end(); ++i)
    printf("%d:%d ", i->first, i->second);
  putchar('\n');
}
#endif

int main()
{
  int t;
  scanf("%d", &t);
  while (t--) {
    int n, b;
    scanf("%d %d", &n, &b);
    int nr_types = 0;
    map<string, int> types;
    vector< map<int, int> > components;
    while (n--) {
      char type[nr_chars_max + 1];
      int price, quality;
      scanf("%s %*s %d %d", type, &price, &quality);
      pair<map<string, int>::iterator, bool> sr =
        types.insert(make_pair(string(type), nr_types));
      if (sr.second) {
        nr_types++;
        components.push_back(map<int, int>());
      }
      pair<map<int, int>::iterator, bool> cr =
        components[sr.first->second].insert(make_pair(quality, price));
      if (!cr.second && cr.first->second > price)
        cr.first->second = price;
    };
    vector< map<int, int> > qualities(nr_types);
    for (map<int, int>::const_iterator k = components[0].begin();
      k != components[0].end(); ++k) {
      int q = k->first, p = k->second;
      if (p <= b)
        qualities[0].insert(make_pair(q, p));
    }
#ifdef DEBUG
    print_qualities(qualities[0]);
#endif
    for (int i = 1; i < nr_types; i++) {
      for (map<int, int>::const_iterator j = qualities[i - 1].begin();
        j != qualities[i - 1].end(); ++j) {
        int quality = j->first, price = j->second;
        for (map<int, int>::const_iterator k = components[i].begin();
          k != components[i].end(); ++k) {
          int q = min(quality, k->first), p = price + k->second;
          if (p <= b) {
            pair<map<int, int>::iterator, bool> qr =
              qualities[i].insert(make_pair(q, p));
            if (!qr.second && qr.first->second > p)
              qr.first->second = p;
          }
        }
      }
#ifdef DEBUG
      print_qualities(qualities[i]);
#endif
    }
    printf("%d\n", qualities[nr_types - 1].rbegin()->first);
  }
  return 0;
}

Saturday, September 24, 2016

UVa 12470 - Tribonacci

Accepted date: 2016-09-24
Run Time: 0.000
Ranking (as of 2016-09-24): 75 out of 400
Language: C++

/*
  UVa 12470 - Tribonacci

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_12470_Tribonacci.cpp
*/

#include <cstdio>

/*
t(k + 3)    1 1 1  t(k + 2)
t(k + 2) =  1 0 0  t(k + 1)
t(k + 1)    0 1 0  t(k)
*/

long long tribonacci(long long n)
{
  const long long modulo = 1000000009;
  long long trib[3][3] = {{1, 1, 1}, {1, 0, 0}, {0, 1, 0}},
    result[3][3]= {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
  while (n) {
    if(n & 1) {
      long long r[3][3] = {};
      for (int i = 0; i < 3; i++)
        for (int j = 0; j < 3; j++)
          for (int k = 0; k < 3; k++)
            r[i][j] = (r[i][j] + result[i][k] * trib[k][j] % modulo) % modulo;
      for (int i = 0; i < 3; i++)
        for (int j = 0; j < 3; j++)
          result[i][j] = r[i][j];
        }
    long long r[3][3]= {};
    for (int i = 0; i < 3; i++)
      for (int j = 0; j < 3; j++)
        for (int k = 0; k < 3; k++)
          r[i][j] = (r[i][j] + trib[i][k] * trib[k][j] % modulo) % modulo;
    for (int i = 0; i < 3; i++)
      for (int j = 0; j < 3; j++)
        trib[i][j] = r[i][j];
    n /= 2;
  }
  return result[0][1];
}

int main()
{
  while (true) {
    long long n;
    scanf("%lld", &n);
    if (!n)
      break;
    printf("%lld\n", tribonacci(n - 1));
  }
  return 0;
}

Friday, September 23, 2016

UVa 12894 - Perfect Flag

Accepted date: 2016-09-23
Run Time: 0.000
Ranking (as of 2016-09-23): 172 out of 382
Language: C++

/*
  UVa 12894 - Perfect Flag

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_12894_Perfect_Flag.cpp
*/

#include <cstdio>

int main()
{
  int T;
  scanf("%d", &T);
  while (T--) {
    int x0, y0, x1, y1, cx, cy, r;
    scanf("%d %d %d %d %d %d %d", &x0, &y0, &x1, &y1, &cx, &cy, &r);
    int l = x1 - x0, w = y1 - y0;
    bool valid = l && w && l * 6 == w * 10 && l == r * 5 &&
      l * 9 == (cx - x0) * 20 && w == (cy - y0) * 2;
    puts((valid) ? "YES" : "NO");
  }
  return 0;
}

Thursday, September 22, 2016

UVa 12657 - Boxes in a Line

Accepted date: 2016-09-22
Run Time: 0.090
Ranking (as of 2016-09-22): 72 out of 388
Language: C++

/*
  UVa 12657 - Boxes in a Line

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_12657_Boxes_in_a_Line.cpp
*/

#include <algorithm>
#include <cstdio>
using namespace std;

const int n_max = 100000;

struct list {
  int value_;
  list *left_, *right_;
} lists[n_max + 1];

void remove(list* l)
{
  l->right_->left_ = l->left_, l->left_->right_ = l->right_;
}

void insert_left(list* ll, list* l)
{
  l->left_->right_ = ll, ll->left_ = l->left_;
  ll->right_ = l, l->left_ = ll;
}

void insert_right(list* rl, list* l)
{
  l->right_->left_ = rl, rl->right_ = l->right_;
  rl->left_ = l, l->right_ = rl;
}

void swap_(list* ll, list* rl)
{
  if (ll->left_ != rl && ll->right_ != rl) {
    ll->left_->right_ = rl, ll->right_->left_= rl;
    rl->left_->right_ = ll, rl->right_->left_ = ll;
    swap(ll->left_, rl->left_);
    swap(ll->right_, rl->right_);
  }
  else if (ll->right_ == rl) {
    ll->left_->right_ = rl, rl->right_->left_ = ll;
    ll->right_ = rl->right_, rl->left_ = ll->left_;
    ll->left_ = rl, rl->right_ = ll;
  }
  else {
    ll->right_->left_ = rl, rl->left_->right_ = ll;
    ll->left_ = rl->left_, rl->right_ = ll->right_;
    ll->right_ = rl, rl->left_ = ll;
  }
}

#ifdef DEBUG
void print_list(bool reverse)
{
  if (reverse)
    for (list* l = lists[0].left_; l != &lists[0]; l = l->left_)
      printf("%d ", l->value_);
  else
    for (list* l = lists[0].right_; l != &lists[0]; l = l->right_)
      printf("%d ", l->value_);
  putchar('\n');
}
#endif

int main()
{
  for (int cn = 1; ; cn++) {
    int n, m;
    if (scanf("%d %d", &n, &m) == EOF)
      break;
    lists[0].left_ = &lists[n], lists[0].right_ = &lists[1];
    for (int i = 1; i < n; i++)
      lists[i].value_ = i,
        lists[i].left_ = &lists[i - 1], lists[i].right_ = &lists[i + 1];
    lists[n].value_ = n,
      lists[n].left_ = &lists[n - 1], lists[n].right_ = &lists[0];
    bool reverse = false;
    while (m--) {
      int c, X, Y;
      scanf("%d", &c);
      if (c != 4)
        scanf("%d %d", &X, &Y);
      switch (c) {
      case 1:
        if (reverse) {
          if (lists[X].left_ != &lists[Y]) {
            remove(&lists[X]);
            insert_right(&lists[X], &lists[Y]);
          }
        }
        else {
          if (lists[X].right_ != &lists[Y]) {
            remove(&lists[X]);
            insert_left(&lists[X], &lists[Y]);
          }
        }
        break;
      case 2:
        if (reverse) {
          if (lists[X].right_ != &lists[Y]) {
            remove(&lists[X]);
            insert_left(&lists[X], &lists[Y]);
          }
        }
        else {
          if (lists[X].left_ != &lists[Y]) {
            remove(&lists[X]);
            insert_right(&lists[X], &lists[Y]);
          }
        }
        break;
      case 3:
        swap_(&lists[X], &lists[Y]);
        break;
      case 4:
        reverse = !reverse;
        break;
      }
#ifdef DEBUG
      print_list(reverse);
#endif
    }
    bool odd = true;
    unsigned int s = 0;
    if (reverse) {
      for (list* l = lists[0].left_; l != &lists[0]; l = l->left_) {
        if (odd)
          odd = false, s += l->value_;
        else
          odd = true;
      }
    }
    else {
      for (list* l = lists[0].right_; l != &lists[0]; l = l->right_) {
        if (odd)
          odd = false, s += l->value_;
        else
          odd = true;
      }
    }
    printf("Case %d: %u\n", cn, s);
  }
  return 0;
}

Wednesday, September 21, 2016

UVa 12563 - Jin Ge Jin Qu hao

Accepted date: 2016-09-21
Run Time: 0.000
Ranking (as of 2016-09-21): 64 out of 386
Language: C++

/*
  UVa 12563 - Jin Ge Jin Qu hao

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_12563_Jin_Ge_Jin_Qu_hao.cpp
*/

#include <algorithm>
#include <cstdio>
using namespace std;

const int n_max = 50, t_max = 180 * n_max, jin_ge_jin_qu = 678;
int ts[n_max + 1][t_max + 1];

int main()
{
  int T;
  scanf("%d", &T);
  for (int c = 1; c <= T; c++) {
    int n, t;
    scanf("%d %d", &n, &t);
    int s = 0;
    for (int i = 1; i <= n; i++) {
      int st;
      scanf("%d", &st);
      for (int j = 1; j <= s + st; j++)
        ts[i][j] = 0;
      ts[i][st] = 1;
      for (int j = 1; j <= s; j++) {
        if (ts[i - 1][j]) {
          ts[i][j] = max(ts[i][j], ts[i - 1][j]);
          if (j + st < t)
            ts[i][j + st] = max(ts[i][j + st], ts[i - 1][j] + 1);
        }
      }
      s += st;
    }
#ifdef DEBUG
    for (int i = 1; i <= s; i++)
      if (ts[n][i])
        printf("%d:%d ", i, ts[n][i]);
    putchar('\n');
#endif
    int max_songs = 0, max_length = 0;
    for (int i = 1; i <= min(s, t); i++)
      if (ts[n][i]) {
        if (max_songs < ts[n][i])
          max_songs = ts[n][i], max_length = i;
        else if (max_songs == ts[n][i] && max_length < i)
          max_length = i;
      }
    printf("Case %d: %d %d\n", c, max_songs + 1, max_length + jin_ge_jin_qu);
  }
  return 0;
}

Monday, September 19, 2016

UVa 533 - Equation Solver

Accepted date: 2016-09-19
Run Time: 0.000
Ranking (as of 2016-09-19): 11 out of 389
Language: C++

/*
  UVa 533 - Equation Solver

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_533_Equation_Solver.cpp
*/

#include <cstdio>
#include <cctype>
#ifndef ONLINE_JUDGE
#include <cassert>
#endif

struct linear_expression {
  int v_, c_;

  linear_expression() : v_(0), c_(0) {}
};

const int nr_chars_max = 100;
const char *ps;

int get_number()
{
  if (isdigit(*ps)) {
    int n = *ps++ - '0';
    while (isdigit(*ps)) {
      n = n * 10 + *ps++ - '0';
    }
    return n;
  }
  else
    return -1;
}

void expression(linear_expression& le);
void term(linear_expression& le);
void factor(linear_expression& le);

void expression(linear_expression& le)
{
  term(le);
  while (*ps == '+' || *ps == '-') {
    char c = *ps++;
    linear_expression le_;
    term(le_);
    if (c == '+')
      le.v_ += le_.v_, le.c_ += le_.c_;
    else
      le.v_ -= le_.v_, le.c_ -= le_.c_;
  }
}

void term(linear_expression& le)
{
  factor(le);
  while (*ps == '*') {
    ps++;
    linear_expression le_;
    factor(le_);
    le.v_ = le.c_ * le_.v_ + le.v_ * le_.c_;
    le.c_ *= le_.c_;
  }
}

void factor(linear_expression& le)
{
  int n = get_number();
  if (n != -1)
    le.c_ = n;
  else if (*ps == 'x')
    ps++, le.v_ = 1;
  else {
#ifndef ONLINE_JUDGE
    assert(*ps == '(');
#endif
    ps++;
    expression(le);
#ifndef ONLINE_JUDGE
    assert(*ps == ')');
#endif
    ps++;
  }
}

int main()
{
  char s[nr_chars_max + 1];
  for (int eq = 1; gets(s); eq++) {
    if (eq > 1)
      putchar('\n');
    ps = s;
    linear_expression lle, rle;
    expression(lle);
#ifdef DEBUG
    printf("%d*x + %d\n",  lle.v_, lle.c_);
#endif
#ifndef ONLINE_JUDGE
    assert(*ps == '=');
#endif
    ps++;
    expression(rle);
#ifdef DEBUG
    printf("%d*x + %d\n",  rle.v_, rle.c_);
#endif
    printf("Equation #%d\n", eq);
    int v = lle.v_, c = lle.c_;
    v -= rle.v_, c -= rle.c_;
    if (v)
      printf("x = %.6lf\n", static_cast<double>(-c) / v);
    else if (c)
      puts("No solution.");
    else
      puts("Infinitely many solutions.");
  
  }
  return 0;
}

Saturday, September 17, 2016

UVa 10058 - Jimmi's Riddles

Accepted date: 2016-09-17
Run Time: 0.000
Ranking (as of 2016-09-17): 154 out of 541
Language: C++

Yet another simple implementation of recursive descent parser.


/*
  UVa 10058 - Jimmi's Riddles

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_10058_Jimmis_Riddles.cpp
*/

#include <algorithm>
#include <iostream>
#include <string>
#include <cstring>
#include <cctype>
using namespace std;

const char *ps, *pws, *pwe;

bool get_word(const char** s, const char** e)
{
  while (isspace(*ps))
    ps++;
  *s = ps;
  while (*ps && !isspace(*ps))
    ps++;
  *e = ps;
  return *s < *e;
}

enum {COMMA, AND, ARTICLE, NOUN, VERB};

struct word {
  int length_;
  const char* s_;
};

word articles[] = {
  {1, "a"}, {3, "the"}
};
const size_t nr_articles = sizeof(articles) / sizeof(word);

word nouns[] = {
  {3, "tom"}, {5, "jerry"}, {5, "goofy"}, {6, "mickey"},
  {5, "jimmy"}, {3, "dog"}, {3, "cat"}, {5, "mouse"}
};
const size_t nr_nouns = sizeof(nouns) / sizeof(word);

word verbs[] = {
  {4, "hate"}, {4, "love"}, {4, "know"}, {4, "like"}
};
const size_t nr_verbs = sizeof(verbs) / sizeof(word);

bool accept(int wn)
{
  if (pws == pwe) {
    if (!get_word(&pws, &pwe))
      return false;
  }
  size_t nr_chars = pwe - pws, i;
  bool result = false;
  switch (wn) {
  case COMMA:
    result = nr_chars == 1 && *pws == ',';
    break;
  case AND:
    result = nr_chars == 3 && !strncmp(pws, "and", 3);
    break;
  case ARTICLE:
    for (i = 0; i < nr_articles; i++)
      if (nr_chars == articles[i].length_ &&
        !strncmp(pws, articles[i].s_, articles[i].length_))
        break;
    result = i < nr_articles;
    break;
  case NOUN:
    for (i = 0; i < nr_nouns; i++)
      if (nr_chars == nouns[i].length_ && !strncmp(pws, nouns[i].s_, nouns[i].length_))
        break;
    result = i < nr_nouns;
    break;
  case VERB:
    for (i = 0; i < nr_verbs; i++)
      if (!strncmp(pws, verbs[i].s_, verbs[i].length_)) {
        if (nr_chars == verbs[i].length_)
          break;
        const char* p = pws + verbs[i].length_;
        for ( ; p < pwe; p++)
          if (*p != 's')
            break;
        if (p == pwe)
          break;
      }
    result = i < nr_verbs;
    break;
  }
  if (result)
    pws = pwe;
  return result;
}

void statement(), action(), active_list(), actor();

void statement()
{
  action();
  while (accept(COMMA))
    action();
}

void action()
{
  active_list();
  if (accept(VERB))
    active_list();
  else
    throw -1;
}

void active_list()
{
  actor();
  while (accept(AND))
    actor();
}

void actor()
{
  if (accept(ARTICLE))
    ;
  if (accept(NOUN))
    ;
  else
    throw -1;
}

int main()
{
  string riddle;
  while (getline(cin, riddle)) {
    ps = pws = pwe = riddle.c_str();
    bool yes = false;
    try {
      statement();
      while (isspace(*pws))
        pws++;
      if (!*pws)
        yes = true;
      else
        throw -1;
    }
    catch (int) {
    }
    cout << ((yes) ? "YES I WILL\n" : "NO I WON'T\n");
  }
  return 0;
}

Friday, September 16, 2016

UVa 134 - Loglan-A Logical Language

Accepted date: 2016-09-16
Run Time: 0.000
Ranking (as of 2016-09-16): 290 out of 808
Language: C++

Another simple implementation of recursive descent parser.


/*
  UVa 134 - Loglan-A Logical Language

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_134_Loglan-A_Logical_Language.cpp
*/

#include <algorithm>
#include <iostream>
#include <string>
#include <cctype>
using namespace std;

string sentence;
const char *ps, *pws, *pwe;

bool get_word_or_name(const char** s, const char** e)
{
  while (isspace(*ps))
    ps++;
  *s = ps;
  while (*ps && !isspace(*ps) && *ps != '.')
    ps++;
  *e = ps;
  return *s < *e;
}

bool is_vowel(char c)
{
  return c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u';
}

enum {A, MOD, BA, DA, LA, NAM, PREDA};

bool accept(int wn)
{
  if (pws == pwe) {
    if (!get_word_or_name(&pws, &pwe))
      return false;
  }
  bool result = false;
  switch (wn) {
  case A:
    result = pwe - pws == 1 && is_vowel(*pws);
    break;
  case MOD:
    result = pwe - pws == 2 && *pws == 'g' && is_vowel(*(pws + 1));
    break;
  case BA:
    result = pwe - pws == 2 && *pws == 'b' && is_vowel(*(pws + 1));
    break;
  case DA:
    result = pwe - pws == 2 && *pws == 'd' && is_vowel(*(pws + 1));
    break;
  case LA:
    result = pwe - pws == 2 && *pws == 'l' && is_vowel(*(pws + 1));
    break;
  case NAM:
    result = pwe > pws && !is_vowel(*(pwe - 1));
    break;
  case PREDA:
    result = pwe - pws == 5 && !is_vowel(*pws) && 
      (!is_vowel(*(pws + 1)) && is_vowel(*(pws + 2)) ||
        is_vowel(*(pws + 1)) && !is_vowel(*(pws + 2))) &&
      !is_vowel(*(pws + 3)) && is_vowel(*(pws + 4));
    break;
  }
  if (result)
    pws = pwe;
  return result;
}

void predclaim(), preds(), predname(), predstring(), statement(), verbpred();

void predclaim()
{
  if (accept(DA))
    preds();
  else {
    predname();
    if (accept(BA))
      preds();
    else
      throw -1;
  }
}

void preds()
{
  predstring();
  while (accept(A))
    predstring();
}

void predname()
{
  if (accept(LA))
    predstring();
  else if (accept(NAM))
    ;
  else
    throw -1;
}

void predstring()
{
  if (accept(PREDA)) {
    while (accept(PREDA))
    ;
  }
  else
    throw -1;
}

void statement()
{
  predname();
  verbpred();
  if (*ps && *ps != '.')
    predname();
}

void verbpred()
{
  if (accept(MOD))
    predstring();
  else
    throw -1;
}

int main()
{
  while (true) {
    string line;
    getline(cin, line);
    if (line[0] == '#')
      break;
    sentence.clear();
    while (true) {
      sentence += line;
      if (sentence.find_first_of('.') != string::npos)
        break;
      sentence += ' ';
      getline(cin, line);
    }
#ifdef DEBUG
    cout << sentence << endl;
#endif
//    transform(sentence.begin(), sentence.end(), sentence.begin(), (int(*)(int))tolower);
    bool good = false;
    try {
      ps = pws = pwe = sentence.c_str();
      statement();
      if (*ps == '.')
        good = true;
      else
        throw -1;
    }
    catch (int) {
      try {
        ps = pws = pwe = sentence.c_str();
        predclaim();
        if (*ps == '.')
          good = true;
      }
      catch (int) {
      }
    }
    cout << ((good) ? "Good\n" : "Bad!\n");
  }
  return 0;
}

Thursday, September 15, 2016

UVa 622 - Grammar Evaluation

Accepted date: 2016-09-15
Run Time: 0.000
Ranking (as of 2016-09-15): 304 out of 680
Language: C++

A simple implementation of recursive descent parser.


/*
  UVa 622 - Grammar Evaluation

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_622_Grammar_Evaluation.cpp
*/

/*
< expression > := < component > | < component > + < expression >
< component > := < factor > | < factor > * < component >
< factor > := < positiveinteger > | (< expression >)
*/

#include <cstdio>
#include <cstring>
#include <cctype>

const int nr_chars_max = 255;

char s[nr_chars_max + 1], *ps;

int positive_integer()
{
  if (isdigit(*ps)) {
    int n = 0;
    do
      n = n * 10 + *ps++ - '0';
    while (isdigit(*ps));
    return n;
  }
  else
    return -1;
}

int expression();
int component();
int factor();

int factor()
{
  int n = positive_integer();
  if (n != -1)
    return n;
  else if (*ps == '(') {
    ps++;
    n = expression();
    if (*ps == ')')
      ps++;
    else
      throw -1;
    return n;
  }
  else {
    throw -1;
    return -1;
  }
}

int component()
{
  int n = factor();
  if (*ps == '*') {
    ps++;
    n *= component();
  }
  return n;
}

int expression()
{
  int n = component();
  if (*ps == '+') {
    ps++;
    n += expression();
  }
  return n;
}

int main()
{
  int n;
  scanf("%d", &n);
  while (n--) {
    scanf("%s", ps = s);
    try {
      int n = expression();
      if (*ps)
        throw -1;
      printf("%d\n", n);
    }
    catch (int e) {
      puts("ERROR");
    }
  }
  return 0;
}

Tuesday, September 13, 2016

UVa 707 - Robbery

Accepted date: 2016-09-13
Run Time: 0.010
Ranking (as of 2016-09-13): 12 out of 392
Language: C++

/*
  UVa 707 - Robbery

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_707_Robbery.cpp
*/

#include <cstdio>

const int W_max = 100, H_max = 100, t_max = 100;
int W, H, t, city[t_max + 1][H_max + 1][W_max + 1];

struct deduction {
  int r_, c_;
} deductions[t_max + 1];

const int nr_moves = 5;
const int moves[nr_moves][2] = {{0, 0}, {0, -1}, {0, 1}, {-1, 0}, {1, 0}};

void deduce(int ti, int r, int c)
{
#ifdef DEBUG
  printf("%d %d %d\n", ti, r, c);
#endif
  if (deductions[ti].r_ == -1)
    deductions[ti].r_ = r, deductions[ti].c_ = c;
  else if (r != deductions[ti].r_ || c != deductions[ti].c_)
    deductions[ti].c_ = -1;
}

int move(int ti, int r, int c)
{
  int& result = city[ti][r][c];
  if (result != -1)
    return result;
  if (ti == t) {
    result = 1;
    deduce(ti, r, c);
  }
  else {
    result = 0;
    for (int i = 0; i < nr_moves; i++) {
      int nr = r + moves[i][0], nc = c + moves[i][1];
      if (nr > 0 && nr <= H && nc > 0 && nc <= W && move(ti + 1, nr, nc)) {
        result = 1;
        deduce(ti, r, c);
      }
    }
  }
  return result;
}

int main()
{
  for (int nr = 1; ; nr++) {
    scanf("%d %d %d", &W, &H, &t);
    if (!W)
      break;
    for (int i = 1; i <= t; i++) {
      for (int j = 1; j <= H; j++)
        for (int k = 1; k <= W; k++)
          city[i][j][k] = -1;
      deductions[i].r_ = deductions[i].c_ = -1;
    }
    int n;
    scanf("%d", &n);
    while (n--) {
      int ti, Li, Ti, Ri, Bi;
      scanf("%d %d %d %d %d", &ti, &Li, &Ti, &Ri, &Bi);
      for (int i = Ti; i <= Bi; i++)
        for (int j = Li; j <= Ri; j++)
          city[ti][i][j] = 0;
    }
    for (int i = 1; i <= H; i++)
      for (int j = 1; j <= W; j++)
        move(1, i, j);
    printf("Robbery #%d:\n", nr);
    if (deductions[t].r_ == -1)
      puts("The robber has escaped.\n");
    else {
      int nr_deductions = 0;
      for (int i = 1; i <= t; i++)
        if (deductions[i].c_ != -1) {
          nr_deductions++;
          printf("Time step %d: The robber has been at %d,%d.\n",
            i, deductions[i].c_, deductions[i].r_);
        }
      if (nr_deductions)
        putchar('\n');
      else
        puts("Nothing known.\n");
    }
  }
  return 0;
}

Monday, September 12, 2016

UVa 1207 - AGTC

Accepted date: 2016-09-12
Run Time: 0.000
Ranking (as of 2016-09-12): 79 out of 481
Language: C++

/*
  UVa 1207 - AGTC

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_1207_AGTC.cpp

  This problem is similar to UVa 164 - String Computer, 
    UVa 526 - String Distance and Transform Process.
*/

#include <cstdio>
#include <cstring>

const int nr_chars_max = 1000;

enum {editMatchOrReplace, editInsert, editDelete};

struct edit_state {
  int cost_; // cost of reaching this state
/*
    int parent_; // parent state
*/
} edite_states[nr_chars_max + 1][nr_chars_max + 1];

int edit_distance(const char* s, const char* t, int sl, int tl)
{
  for (int i = 0; i < nr_chars_max + 1; i++) {
    // first row
    edite_states[0][i].cost_ = i;
/*
    edite_states[0][i].parent_ =  (i) ? editInsert : -1;
*/
    // first column
        edite_states[i][0].cost_ = i;
/*
    edite_states[i][0].parent_ = (i) ? editDelete : -1;
*/
  }

  for (int i = 1; i < sl; i++)
    for (int j = 1; j < tl; j++) {
      int costs[editDelete - editMatchOrReplace + 1];
      // For inserting or deleting or replacing characters, 
      // cost is one, while for maching characters, cost is zero.
      costs[editMatchOrReplace] =
        edite_states[i - 1][j - 1].cost_ + ((s[i] == t[j]) ? 0 : 1);
      costs[editInsert] = edite_states[i][j - 1].cost_ + 1;
      costs[editDelete] = edite_states[i - 1][j].cost_ + 1;
      edite_states[i][j].cost_ = costs[editMatchOrReplace];
/*
      edite_states[i][j].parent_ = editMatchOrReplace;
*/
      for (int k = editInsert; k <= editDelete; k++)
        if (costs[k] < edite_states[i][j].cost_) {
          edite_states[i][j].cost_ = costs[k];
/*
          edite_states[i][j].parent_ = k;
*/
        }
    }
  return edite_states[sl - 1][tl - 1].cost_;
} 

/*
void reconstruct_path(char* s, char* t, int i, int j, int& p, int& n)
{
  int parent = edite_states[i][j].parent_;
  if (parent == -1)
    p = n = 1;
  else if (parent == editMatchOrReplace) {
    reconstruct_path(s, t, i - 1,j - 1, p, n);
    if (s[i] != t[j]) {
      printf("%d Replace %d,%c\n", n, p, t[j]);
      n++;
    }
    p++;
  }
  else if (parent == editInsert) {
    reconstruct_path(s, t, i, j - 1, p, n);
    printf("%d Insert %d,%c\n", n, p, t[j]);
    p++; n++;
  }
  else if (parent == editDelete) {
    reconstruct_path(s, t, i - 1, j, p, n);
    printf("%d Delete %d\n", n, p);
    n++;
  }
}
*/

char s[nr_chars_max + 2], t[nr_chars_max + 2];

int main()
{
  while (true) {
    s[0] = t[0] = ' ';
    int sl, tl;
    if (scanf("%d %s", &sl, &s[1]) == EOF)
      break;
    scanf("%d %s", &tl, &t[1]);
    int d = edit_distance(s, t, sl + 1, tl + 1);
    printf("%d\n", d);
  }
  return 0;
}

Sunday, September 11, 2016

UVa 12526 - Cellphone Typing

Accepted date: 2016-09-11
Run Time: 0.460
Ranking (as of 2016-09-11): 92 out of 399
Language: C++

/*
  UVa 12526 - Cellphone Typing

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_12526_Cellphone_Typing.cpp
*/

#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;

const int N_max = 100000, nr_chars_max = 80;
struct word {
  char s_[nr_chars_max + 1];

  bool operator<(const word& w) const {return strcmp(s_, w.s_) < 0;}
} words[N_max];

int typing(word& w, int i, int low, int high, int nr_typing)
{
  if (low == high || !w.s_[i])
    return nr_typing;
  char c = w.s_[i + 1];
  w.s_[i + 1] = '\0';
  int l = lower_bound(words + low, words + high, w) - words;
  w.s_[i]++;
  int h = lower_bound(words + low, words + high, w) - words;
  w.s_[i]--, w.s_[i + 1] = c;
  if (i && l == low && h == high)
    ;
  else
    nr_typing++;
  return typing(w, i + 1, l, h, nr_typing);
}

int main()
{
  int N;
  while (scanf("%d", &N) != EOF) {
    for (int i = 0; i < N; i++)
      scanf("%s", words[i].s_);
    sort(words, words + N);
    int nr_typings = 0;
    for (int i = 0; i < N; i++) {
      word w;
      strcpy(w.s_, words[i].s_);
      int nr = typing(w, 0, 0, N, 0);
#ifdef DEBUG
      printf("%s: %d\n", w.s_, nr);
#endif
      nr_typings += nr;
    }
    printf("%.2lf\n", static_cast<double>(nr_typings) / N);
  }
  return 0;
}

Thursday, September 8, 2016

UVa 11058 - Encoding

Accepted date: 2016-09-08
Run Time: 0.000
Ranking (as of 2016-09-08): 10 out of 394
Language: C++

/*
  UVa 11058 - Encoding

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_11058_Encoding.cpp
*/

#include <cstdio>
#include <cstring>

int main()
{
  const int nr_chars = 128, nr_letters = 'z' - 'a' + 1, S_max = 100;
  for (int N = 1; ; N++) {
    char S[S_max + 1], s[S_max + 1];
    if (scanf("%s", S) == EOF)
      break;
    char replacements[nr_chars];
    for (int i = 0; i < nr_letters; i++) {
      char c;
      scanf("%s", &c);
      replacements['a' + i] = c;
    }
    char *p, *q;
    for (p = S, q = s; *p; p++, q++)
      *q = replacements[*p];
    *q = '\0';
#ifdef DEBUG
    printf("%s\n", s);
#endif
    int R;
    scanf("%d", &R);
    while (R--) {
      int P;
      char X, Y;
      scanf("%d %c %c", &P, &X, &Y);
      for (p = S + P, q = s + P; *p; p++, q++)
        if (*p == X)
          *q = Y;
    }
    printf("Case #%d: The encoding string is %s.\n\n", N, s);
  }
  return 0;
}

UVa 11107 - Life Forms

Accepted date: 2016-09-07
Run Time: 0.310
Ranking (as of 2016-09-08): 148 out of 486
Language: C++

Note that suffix array construction is based on a sample code that can be downloaded from Competitive Programming support materials site, with a few modifications.
The rest of the code in the main function is a variation of Longest Common Substring calculation.


/*
  UVa 11107 - Life Forms

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_11107_Life_Forms.cpp
*/

#include <algorithm>
#include <map>
#include <cstdio>
#include <cstring>
using namespace std;

typedef pair<int, int> ii;

#define MAX_N 101010                         // second approach: O(n log n)
char T[MAX_N];                   // the input string, up to 100K characters
int n;                                        // the length of input string
int RA[MAX_N], tempRA[MAX_N];        // rank array and temporary rank array
int SA[MAX_N], tempSA[MAX_N];    // suffix array and temporary suffix array
int c[MAX_N];                                    // for counting/radix sort

char P[MAX_N];                  // the pattern string (for string matching)
int m;                                      // the length of pattern string

int Phi[MAX_N];                      // for computing longest common prefix
int PLCP[MAX_N];
int LCP[MAX_N];  // LCP[i] stores the LCP between previous suffix T+SA[i-1]
                                              // and current suffix T+SA[i]

bool cmp(int a, int b) { return strcmp(T + a, T + b) < 0; }      // compare

void constructSA_slow() {               // cannot go beyond 1000 characters
  for (int i = 0; i < n; i++) SA[i] = i; // initial SA: {0, 1, 2, ..., n-1}
  sort(SA, SA + n, cmp); // sort: O(n log n) * compare: O(n) = O(n^2 log n)
}

void countingSort(int k) {                                          // O(n)
  int i, sum, maxi = max(300, n);   // up to 255 ASCII chars or length of n
  memset(c, 0, sizeof c);                          // clear frequency table
  for (i = 0; i < n; i++)       // count the frequency of each integer rank
    c[i + k < n ? RA[i + k] : 0]++;
  for (i = sum = 0; i < maxi; i++) {
    int t = c[i]; c[i] = sum; sum += t;
  }
  for (i = 0; i < n; i++)          // shuffle the suffix array if necessary
    tempSA[c[SA[i]+k < n ? RA[SA[i]+k] : 0]++] = SA[i];
  for (i = 0; i < n; i++)                     // update the suffix array SA
    SA[i] = tempSA[i];
}

void constructSA() {         // this version can go up to 100000 characters
  int i, k, r;
  for (i = 0; i < n; i++) RA[i] = T[i];                 // initial rankings
  for (i = 0; i < n; i++) SA[i] = i;     // initial SA: {0, 1, 2, ..., n-1}
  for (k = 1; k < n; k <<= 1) {       // repeat sorting process log n times
    countingSort(k);  // actually radix sort: sort based on the second item
    countingSort(0);          // then (stable) sort based on the first item
    tempRA[SA[0]] = r = 0;             // re-ranking; start from rank r = 0
    for (i = 1; i < n; i++)                    // compare adjacent suffixes
      tempRA[SA[i]] = // if same pair => same rank r; otherwise, increase r
      (RA[SA[i]] == RA[SA[i-1]] && RA[SA[i]+k] == RA[SA[i-1]+k]) ? r : ++r;
    for (i = 0; i < n; i++)                     // update the rank array RA
      RA[i] = tempRA[i];
    if (RA[SA[n-1]] == n-1) break;               // nice optimization trick
} }

void computeLCP_slow() {
  LCP[0] = 0;                                              // default value
  for (int i = 1; i < n; i++) {                // compute LCP by definition
    int L = 0;                                       // always reset L to 0
    while (T[SA[i] + L] == T[SA[i-1] + L]) L++;      // same L-th char, L++
    LCP[i] = L;
} }

void computeLCP() {
  int i, L;
  Phi[SA[0]] = -1;                                         // default value
  for (i = 1; i < n; i++)                            // compute Phi in O(n)
    Phi[SA[i]] = SA[i-1];    // remember which suffix is behind this suffix
  for (i = L = 0; i < n; i++) {             // compute Permuted LCP in O(n)
    if (Phi[i] == -1) { PLCP[i] = 0; continue; }            // special case
    while (T[i + L] != '.' && T[i + L] == T[Phi[i] + L]) L++; // L increased max n times
    PLCP[i] = L;
    L = max(L-1, 0);                             // L decreased max n times
  }
  for (i = 0; i < n; i++)                            // compute LCP in O(n)
    LCP[i] = PLCP[SA[i]];   // put the permuted LCP to the correct position
}

ii stringMatching() {                      // string matching in O(m log n)
  int lo = 0, hi = n-1, mid = lo;              // valid matching = [0..n-1]
  while (lo < hi) {                                     // find lower bound
    mid = (lo + hi) / 2;                              // this is round down
    int res = strncmp(T + SA[mid], P, m);  // try to find P in suffix 'mid'
    if (res >= 0) hi = mid;        // prune upper half (notice the >= sign)
    else          lo = mid + 1;           // prune lower half including mid
  }                                      // observe `=' in "res >= 0" above
  if (strncmp(T + SA[lo], P, m) != 0) return ii(-1, -1);    // if not found
  ii ans; ans.first = lo;
  lo = 0; hi = n - 1; mid = lo;
  while (lo < hi) {            // if lower bound is found, find upper bound
    mid = (lo + hi) / 2;
    int res = strncmp(T + SA[mid], P, m);
    if (res > 0) hi = mid;                              // prune upper half
    else         lo = mid + 1;            // prune lower half including mid
  }                           // (notice the selected branch when res == 0)
  if (strncmp(T + SA[hi], P, m) != 0) hi--;                 // special case
  ans.second = hi;
  return ans;
} // return lower/upperbound as first/second item of the pair, respectively

ii LRS() {                 // returns a pair (the LRS length and its index)
  int i, idx = 0, maxLCP = -1;
  for (i = 1; i < n; i++)                         // O(n), start from i = 1
    if (LCP[i] > maxLCP)
      maxLCP = LCP[i], idx = i;
  return ii(maxLCP, idx);
}

const int nr_life_forms_max = 100, nr_chars_max = 1000;
int nr_life_forms, lengths[nr_life_forms_max], counters[nr_life_forms_max];
int Owners[MAX_N];

int owner(int idx)
{
  for (int i = 0, length = lengths[i] + 1; ; i++, length += lengths[i] + 1) {
    if (idx < length - 1)
      return i;
    else if (idx == length - 1)
      return -1;
  }
}

/*
int owner(int idx) { return (idx < n-m-1) ? 1 : 2; }
*/

ii LCS() {                 // returns a pair (the LCS length and its index)
  int i, idx = 0, maxLCP = -1;
  for (i = 1; i < n; i++)                         // O(n), start from i = 1
    if (owner(SA[i]) != owner(SA[i-1]) && LCP[i] > maxLCP)
      maxLCP = LCP[i], idx = i;
  return ii(maxLCP, idx);
}

int main()
{
  bool printed = false;
  while (true) {
    scanf("%d", &nr_life_forms);
    if (!nr_life_forms)
      break;
    if (printed)
      putchar('\n');
    else
      printed = true;
    if (nr_life_forms == 1) {
      scanf("%s", T);
      puts(T);
      continue;
    }
    n = 0;
    for (int i = 0; i < nr_life_forms; i++) {
      scanf("%s", T + n);
      lengths[i] = strlen(T + n);
      n += lengths[i];
      T[n++] = '.';
    }
    T[n] = '\0';
    constructSA(); // O(n log n)
    computeLCP(); // O(n)
    for (int i = 0; i < n; i++)
      Owners[i] = owner(SA[i]);
#ifdef DEBUG
    printf("\nThe LCP information of '%s':\n", T);
    printf("i     SA[i] LCP[i] Owner Suffix\n");
    for (int k = 0; k < n; k++)
      printf("%4d  %4d  %4d   %4d  %s\n", k, SA[k], LCP[k], Owners[k], T + SA[k]);
#endif
    int lcs_length = 0;
    memset(counters, 0, sizeof(counters));
    for (int i = nr_life_forms, j = nr_life_forms, total = 0; j < n; ) {
      if (total <= nr_life_forms / 2) {
        if (!counters[Owners[j++]]++)
          ++total;
      }
      if (total > nr_life_forms / 2) {
        lcs_length = max(lcs_length, LCP[min_element(LCP + i + 1, LCP + j) - LCP]);
#ifdef DEBUG
        printf("LCS [%d, %d): %d\n", i, j, lcs_length);
#endif
        if (!--counters[Owners[i++]])
          --total;
      }
    }
    if (!lcs_length) {
      puts("?");
      continue;
    }
    int psa = -1;
    memset(counters, 0, sizeof(counters));
    for (int i = nr_life_forms, j = nr_life_forms, total = 0; j < n; ) {
      if (total <= nr_life_forms / 2) {
        if (!counters[Owners[j++]]++)
          ++total;
      }
      if (total > nr_life_forms / 2) {
        int k = min_element(LCP + i + 1, LCP + j) - LCP;
        if (LCP[k] == lcs_length &&
          (psa == -1 || strncmp(T + psa, T + SA[k], lcs_length))) {
          psa = SA[k];
          char c = T[psa + lcs_length];
          T[psa + lcs_length] = '\0';
#ifdef DEBUG
          printf("LCS [%d, %d): %s\n", i, j, T + psa);
#else
          puts(T + psa);
#endif
          T[psa + lcs_length] = c;
        }
        if (!--counters[Owners[i++]])
          --total;
      }
    }
  }
  return 0;
}