Monday, December 26, 2016

UVa 10146 - Dictionary

Accepted date: 2016-12-206
Run Time: 0.030
Ranking (as of 2016-12-26): 6 out of 370
Language: C++

/*
  UVa 10146 - Dictionary

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

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

const int nr_chars_max = 10;

const char* spaces[] = {
  "", " ", "  ", "   ", "    ", "     ", "      ", "       ", "        ", 
  "         ", "          "
};

int main()
{
  int nr_cases;
  scanf("%d", &nr_cases);
  while (getchar() != '\n')
    ;
  char s[nr_chars_max + 1], t[nr_chars_max + 1];
  gets(s);
  while (nr_cases--) {
    gets(s);
    puts(s);
    char *previous = s, *current = t;
    int nr_spaces = 1;
    while (gets(current) && current[0]) {
      int i;
      for (i = 0; i < nr_spaces; i++)
        if (!previous[i] || !current[i] || previous[i] != current[i])
          break;
      printf("%s%s\n", spaces[i], current);
      nr_spaces = i + 1;
      swap(previous, current);
    }
    if (nr_cases)
      putchar('\n');
  }
  return 0;
}

Sunday, December 25, 2016

UVa 12205 - Happy Telephones

Accepted date: 2016-12-25
Run Time: 0.040
Ranking (as of 2016-12-25): 22 out of 362
Language: C++

First, applied the line sweep algorithm to calculate the number of connections at each start/stop time of the telephone calls.
For a given interval, found the number of calls at the start time of the interval and then iterated over the telephone call times till the end time of the interval and added the phone calls that started during the interval.


/*
  UVa 12205 - Happy Telephones

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

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

const int N_max = 10000, M_max = 100;

struct event {
  int s_; // 0 for start, 1 for stop
  int t_; // time

  event() {}
  event(int s, int t) : s_(s), t_(t) {}
  bool operator<(const event& e) const {
    if (t_ != e.t_)
      return t_ < e.t_;
    else
      return s_ > e.s_;
  }
} events[N_max * 2];

int main()
{
  while (true) {
    int N, M;
    scanf("%d %d", &N, &M);
    if (!N)
      break;
    int n = 0;
    while (N--) {
      int s, d;
      scanf("%*d %*d %d %d", &s, &d);
      events[n].s_ = 0, events[n].t_ = s;
      n++;
      events[n].s_ = 1, events[n].t_ = s + d;
      n++;
    }
    sort(events, events + n);
#ifdef DEBUG
    for (int i = 0; i < n; i++)
      printf("%d:%d%c", events[i].t_, events[i].s_, ((i < n - 1) ? ' ' : '\n'));
#endif
    int nr = 0;
    map<int, int> nr_calls; // key is the time, value is the number of calls from the time
    for (int i = 0; i < n; i++) {
      if (!events[i].s_)
        nr++;
      else
        nr--;
      nr_calls[events[i].t_] = nr;
    }
#ifdef DEBUG
    for (map<int, int>::const_iterator i = nr_calls.begin(); i != nr_calls.end(); ++i)
      printf("%d:%d ", i->first, i->second);
    putchar('\n');
#endif
    while (M--) {
      int s, d;
      scanf("%d %d", &s, &d);
      nr = 0;
      map<int, int>::const_iterator i = nr_calls.upper_bound(s);
      if (i != nr_calls.end()) {
#ifdef DEBUG
        printf("%d:%d\n", i->first, i->second);
#endif
        if (i != nr_calls.begin())
          nr = (--i)->second;
        int j = upper_bound(events, events + n, event(0, s)) - events;
#ifdef DEBUG
        if (j < n)
          printf("%d:%d\n", events[j].t_, events[j].s_);
#endif
        for ( ; j < n && events[j].t_ < s + d; j++)
          if (!events[j].s_)
            nr++;
      }
      printf("%d\n", nr);
    }
  }
  return 0;
}

Friday, December 23, 2016

UVa 12506 - Shortest Names

Accepted date: 2016-12-23
Run Time: 0.010
Ranking (as of 2016-12-23): 31 out of 363
Language: C++

Used trie.
During the construction of trie, counted the number of occurrences of each trie node.
Then, treversed the trie and summed up the number of occurrences of letters except for the nodes whose parent node has the occurrence counter value of 1.


/*
  UVa 12506 - Shortest Names

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

#include <cstdio>
#include <cstring>

const int nr_letters = 'z' - 'a' + 1, nr_chars_max = 1000000;
char name[nr_chars_max + 1];

struct trie_node {
  static int ctrs_[nr_letters];

  int ctr_;
  trie_node* children_[nr_letters];

  trie_node() : ctr_(0) {
    memset(children_, 0, sizeof(children_));
  }
  ~trie_node() {
    for (int i = 0; i < nr_letters; i++)
      delete children_[i];
  }
  void insert(const char* s);
  void count_prefix(int ci);
};

int trie_node::ctrs_[nr_letters];

void trie_node::insert(const char* s)
{
  trie_node* p = this;
  for (int i = 0, length = strlen(s); i < length; i++) {
    int j = s[i] - 'a';
    if (!p->children_[j])
      p->children_[j] = new trie_node();
    p = p->children_[j];
    p->ctr_++;
  }
}

void trie_node::count_prefix(int ci)
{
  ctrs_[ci] += ctr_;
  if (ctr_ > 1)
    for (int i = 0; i < nr_letters; i++)
      if (children_[i])
        children_[i]->count_prefix(i);
}

int main()
{
  int T;
  scanf("%d", &T);
  while (T--) {
    int n;
    scanf("%d", &n);
    memset(trie_node::ctrs_, 0, sizeof(trie_node::ctrs_));
    trie_node* root = new trie_node();
    while (n--) {
      scanf("%s", name);
      root->insert(name);
    }
    for (int i = 0; i < nr_letters; i++)
      if (root->children_[i])
        root->children_[i]->count_prefix(i);
    int ctr = 0;
    for (int i = 0; i < nr_letters; i++)
      ctr += trie_node::ctrs_[i];
    printf("%d\n", ctr);
    delete root;
  }
  return 0;
}

Sunday, December 11, 2016

UVa 12467 - Secret Word

Accepted date: 2016-12-11
Run Time: 0.020
Ranking (as of 2016-12-11): 3 out of 363
Language: C++

Applied KMP (Knuth-Morris-Pratt) algorithm where patten is an input string and text is the reverse of the input string.


/*
  UVa 12467 - Secret Word

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

#include <cstdio>
#include <cstring>

const int nr_chars_max = 1000000;
char S[nr_chars_max + 1];
int lps[nr_chars_max];
  // length of the maximum matching proper prefix which is also a suffix of S[0..i]

int main()
{
  int T;
  scanf("%d", &T);
  while (T--) {
    scanf("%s", S);
    int n = strlen(S);
    // apply KMP (Knuth-Morris-Pratt) algorithm 
    // where patten is an input string and text is the reverse of the input string
    // calculate lps[]
    lps[0] = 0;
    for (int i = 1, length = 0 /* length of the previous longest prefix suffix */;
      i < n; ) {
      if (S[i] == S[length])
        lps[i++] = ++length;
          else {
          if (length)
          length = lps[length - 1];
              else
                  lps[i++] = 0;
      }
    }
    int max_length = 0, max_i;
    for (int i = n - 1, j = 0; i >= 0; ) {
      if (i >= 0 && S[j] == S[i])
        j++, i--;
      if (j > max_length)
        max_length = j, max_i = i + 1;
      if (j == n)
        j = lps[j - 1];
      else if (i >= 0 && S[j] != S[i]) {
        if (j)
          j = lps[j - 1];
        else
          i--;
      }
    }
#ifdef DEBUG
    printf("%d %d\n", max_i, max_length);
#endif
    S[max_i + max_length] = '\0';
    puts(&S[max_i]);
  }
  return 0;
}

Friday, December 9, 2016

UVa 11515 - Cranes

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

Applied dynamic programming.
areas[i] is the areas with the bitmap i of cranes' usage where each bit of i corresponds to the i-th crane.


/*
  UVa 11515 - Cranes

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

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

const int C_max = 15;

struct crane {
  int x_, y_, r_;
} cranes[C_max];

bool overlapped[C_max][C_max];
  // overlapped[i][j] is true 
  // if the covering areas of i-th crane and j-th crane are overlapped
int areas[1 << C_max];
  // areas[i] is the areas with the bitmap i of cranes' usage

int main()
{
  int t;
  scanf("%d", &t);
  while (t--) {
    int C;
    scanf("%d", &C);
    for (int i = 0; i < C; i++)
      scanf("%d %d %d", &cranes[i].x_, &cranes[i].y_, &cranes[i].r_);
    memset(overlapped, 0, sizeof(overlapped));
    for (int i = 0; i < C - 1; i++)
      for (int j = i + 1; j < C; j++) {
        int dx = cranes[i].x_ - cranes[j].x_, dy = cranes[i].y_ - cranes[j].y_,
          dr = cranes[i].r_ + cranes[j].r_;
        if (dx * dx + dy * dy <= dr * dr)
          overlapped[i][j] = overlapped[j][i] = true;
      }
    memset(areas, 0, sizeof(int) * (1 << C));
    areas[1] = cranes[0].r_ * cranes[0].r_;
#ifdef DEBUG
    printf("[1]:%d\n", areas[1]);
#endif
    for (int i = 1, ib = 1 << 1; i < C; i++, ib <<= 1) {
      int a = cranes[i].r_ * cranes[i].r_;
      for (int j = 1; j < ib; j++)
        if (areas[j]) {
          int k, kb;
          for (k = 0, kb = 1; k < i; k++, kb <<= 1)
            if (j & kb && overlapped[i][k])
              break;
          if (k == i) // not overlapped
            areas[j | ib] = areas[j] + a;
        }
      areas[ib] = a;
#ifdef DEBUG
      for (int j = 1; j < 1 << ib; j++)
        if (areas[j])
          printf("[%d]:%d ", j, areas[j]);
      putchar('\n');
#endif
    }
    int max_area = 0;
    for (int j = 1; j < 1 << C; j++)
      max_area = max(max_area, areas[j]);
    printf("%d\n", max_area);
  }
  return 0;
}

Sunday, November 27, 2016

UVa 158 - Calendar

Accepted date: 2016-11-27
Run Time: 0.000
Ranking (as of 2016-11-27): 122 out of 365
Language: C++

For clarifying the problem description, see 158 - Calendar - UVa OJ Board - UVa Online Judge.
For a specified date, calculated the number of days from the date and the number of stars ('*') that should be printed of each anniversary, and then printed the anniversaries that should be printed (i.e., that have at least one stars).


/*
  UVa 158 - Calendar

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

#include <algorithm>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cctype>
using namespace std;

const int nr_chars_max = 255;

struct anniversary {
  int i_;
  int d_, m_, p_;
  int nr_days_; // number of days from the specified date
  int nr_stars_; // number of stars that should be printed
  anniversary(int i) : i_(i) {}

  bool operator<(const anniversary& a) const
  {
    if (nr_days_ != a.nr_days_)
      return nr_days_ < a.nr_days_;
    else if (!nr_days_)
      return i_ < a.i_;
    else if (nr_stars_ != a.nr_stars_)
      return nr_stars_ > a.nr_stars_;
    else
      return i_ < a.i_;
  }
};

struct description {
  char s_[nr_chars_max + 1];

  description() {}
};

vector<anniversary> anniversaries;
vector<description> descriptions;

inline bool is_leap_year(int year)
{
  if (!(year % 400))
    return true;
  else if (!(year % 100))
    return false;
  else if (!(year % 4))
    return true;
  else
    return false;
}

int get_number_of_days(int year) // return the number of days of given year
{
  return (is_leap_year(year)) ? 366 : 365;
}

int get_number_of_days(int year, int month, int date)
// return the number of days from the first day of given year
{
  const int nr_days[] = {0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
    // nr_days[i] is the number of days before the first day of i-th month
  const int nr_days_leap_year[] = {0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335};
    // nr_days[i] is the number of days before the first day of i-th month for leap years
  int nd = date;
  nd += (is_leap_year(year)) ? nr_days_leap_year[month] : nr_days[month];
  return nd;
}

const char* stars[] = {
  " *TODAY* ", " *       ", " **      ", " ***     ",
  " ****    ", " *****   ", " ******  ", " ******* "
};

int main()
{
  int year;
  scanf("%d", &year);
  while (getchar() != '\n')
    ;
  char s[nr_chars_max + 1];
  int nr_anniversaries = 0;
  while (true) {
    gets(s);
    if (s[0] != 'A')
      break;
    anniversaries.push_back(anniversary(nr_anniversaries)),
      descriptions.push_back(description());
    char* p;
    anniversary& a = anniversaries.back();
    a.d_ = strtol(&s[1], &p, 10);
    a.m_ = strtol(p, &p, 10);
    a.p_ = strtol(p, &p, 10);
    while (isspace(*p))
      p++;
    strcpy(descriptions.back().s_, p);
    nr_anniversaries++;
  }
  bool printed = false;
  while (s[0] != '#') {
    if (printed)
      putchar('\n');
    else
      printed = true;
    char* p;
    int date = strtol(&s[1], &p, 10);
    int month = strtol(p, NULL, 10);
    int nr_days = get_number_of_days(year, month, date);
    for (int i = 0; i < nr_anniversaries; i++) {
      anniversary& a = anniversaries[i];
      int nr = (a.m_ < month || a.m_ == month && a.d_ < date) ?
        get_number_of_days(year) + get_number_of_days(year + 1, a.m_, a.d_) :
        get_number_of_days(year, a.m_, a.d_);
      a.nr_days_ = nr - nr_days;
      a.nr_stars_ = (a.nr_days_ <= 7) ? a.p_ - a.nr_days_ + 1: -1;
    }
    sort(anniversaries.begin(), anniversaries.end());
    printf("Today is:%3d%3d\n", date, month);
    for (int i = 0; i < nr_anniversaries; i++) {
      const anniversary& a = anniversaries[i];
      if (/* a.nr_days_ > 7 || */ a.nr_stars_ <= 0)
        break;
      printf("%3d%3d%s%s\n", a.d_, a.m_,
        ((a.nr_days_) ? stars[a.nr_stars_] : stars[0]), descriptions[a.i_].s_);
    }
    gets(s);
  }
  return 0;
}

Thursday, November 24, 2016

UVa 12186 - Another Crisis

Accepted date: 2016-11-24
Run Time: 0.070
Ranking (as of 2016-11-24): 56 out of 403
Language: C++

Applied dynamic programming.
Caluculated the number of workers who should file a petition to a boss by choosing the necessary number of subordinates by ascending order of their workers who, in turn, should file a petition to them.
Did this calculation recursively.


/*
  UVa 12186 - Another Crisis

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

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

const int N_max = 100000;
int N;
double T;
vector<int> subordinates[N_max + 1];
int nr_workers[N_max + 1];
  // nr_workds[i] is the number of workers who should file a petition to i-th boss

int file_petitions(int bi)
{
  int& nr = nr_workers[bi];
  if (nr != -1)
    return nr;
  const vector<int>& sbs = subordinates[bi];
  if (sbs.empty())
    return nr = 1;
  vector<int> nrs;
  for (size_t i = 0; i < sbs.size(); i++)
    nrs.push_back(file_petitions(sbs[i]));
  sort(nrs.begin(), nrs.end());
  nr = 0;
  for (size_t i = 0, min_nr = static_cast<size_t>(ceil(sbs.size() * T)); i < min_nr; i++)
    nr += nrs[i];
  return nr;
}

int main()
{
  while (true) {
    scanf("%d %lf", &N, &T);
    if (!N)
      break;
    T /= 100.0;
    for (int i = 0; i <= N; i++) {
      subordinates[i].clear();
      nr_workers[i] = -1;
    }
    for (int i = 1; i <= N; i++) {
      int Bi;
      scanf("%d", &Bi);
      subordinates[Bi].push_back(i);
    }
    printf("%d\n", file_petitions(0));
#ifdef DEBUG
    for (int i = 0; i <= N; i++)
      printf("%d:%d%c", i, nr_workers[i], ((i < N) ? ' ' : '\n'));
#endif
  }
  return 0;
}