One Point Solution

  • Subscribe to our RSS feed.
  • Twitter
  • StumbleUpon
  • Reddit
  • Facebook
  • Digg

Monday, 10 September 2012

Codeforces #137 (div2) C. Reducing Fractions - update

Posted on 10:53 by Unknown

I intended to return to participating in Codeforces. Today there was a division 2 match which would be good to restart engines. It didn't go so well at first, with site issues at the announced start time. Then they delayed the start of the match by 15 minutes. I had to wait more time.

Eventually I started by solving problem C. Things were going great until I tried to submit. But I could not. At first I thought it was a bug that I had in the past in division 2 matches - That "unofficial" coders were not able to submit due to a bug. But it turns out that I was just not registered. Which is strange, as I remember that around 1 hour before the contest I clicked register and had to login. And then I remember the register button not appearing anymore, so I thought I registered... Oh well.

C. Reducing Fractions

Link to problem statement

Ok, so, let us reduce a fraction. Unfortunately the numerator is expressed as a product of up to 105 numbers each from 1 to 107 and the denominator as well. The result must be printed using the same format.

Of course we cannot just multiply and then reduce. But either way, each number in the product is either going to be a prime number smaller than 107 or a composite composed of prime numbers less than 107. We could actually just keep two arrays. Each counting the number of times a prime factor appears in total in the numerator and the denominator. After getting these arrays, we can do the reduction easily: For example, let us say we have 20*6 as numerator and 2*7 as denominator. Then we have that 2 appears 3 times in total in the numerator (20 has 2, 6 has 1) and once in the denominator. Simply subtract the minimum count for each prime factor - Thus we have that in the reduced fraction, 2 will appear once in the numerator and 0 times in the denominator.

Some analysis. Each number from 1 to 107 has at most log(X) prime factors. So in total the subtraction part will take O(n * log(X)) for X <= 107. The real complication comes when extracting the prime factors of each number.

I am not sure if the usual O(sqrt(X)) algorithm to extract prime factors would be fast enough, 105*sqrt(107) might be too much for 2 seconds. But in fact, we can make an algorithm that is quite fast at extracting all prime factors of a lot of numbers with a fixed bound. The trick is to use a modified version of the Sieve of Eratosthenes, that instead of only marking if a number is prime or not, marks the number's first prime factor (for a prime number, the result is itself). By precalculating each number's first prime factor you can then use an iterative algorithm to extract all the prime factors of a number in O(log(X)) time (exactly the number of prime factors).

The second issue is, once you have the reduced counts of each prime factor, how to rebuild the two lists of integers in the original format. My intuition tells me that just multiplying each available factor from smallest to largest until the limit of 10/ is reached for an element (and then skip to the next) should be fast enough. Assuming that the original input was also in this format.

old wrong code was here

It seemed like a good problem. Approachable but not without tricks you had to do and suspense (still not sure it is guaranteed to always follow the required conditions for the output.

After figuring out I was not registered, I stopped caring for the match. Perhaps will try to make a virtual context for it, simulating the time I spent in this problem (I finished coding and testing it at 12:11).

Update: I tried it in practice and I failed test 42. Most likely because of an assert related to the limit on the number of integers in the output. Such a high test number tells me this was not even in the sample tests, yet it changes the problem as it means it is not trivial to correctly build the results.

But instantly after, it occurred to me that there is a simple idea for an algorithm that would be guaranteed to follow the conditions. Simply, iterate through each element of a, and for each of its prime factors, subtract it from the number of times that factor should appear, if the current count is 0, remove the factor from the element. Do the same with b.

int n, m; 
int a[100000];
int b[100000];

const int MAX = 10000000;
int firstFactor[MAX+1];

int countA[MAX+1];
int countB[MAX+1];


void addCounts(int x, int * counts)
{
// How to extract prime factors from a number x.
// counts[] stores the number of times each prime factor appears.
while(x != 1) {
int p = firstFactor[x];
// just divide
while (x % p == 0) {
x /= p;
counts[p]++;
}
//the new value of x is not a multiple of p, and thus will have a
// different value for firstFactor[x] - the next prime factor...
}
}

// Rebuild the set of integers for the output.
// counts[] stores the number of times each prime factor should appear.
void buildIt(int* counts, int* res, int & t)
{
for (int i=0; i<t; i++) {
int x = res[i];
while (x > 1) {
int p = firstFactor[x];
x /= p;
if ( counts[p] > 0) {
counts[p]--;
} else { //remove it
res[i] /= p;
}
}
}
}
void solve()
{
memset(countA, 0, sizeof(countA));
memset(countB, 0, sizeof(countB));
for (int i=0; i<n; i++) {
addCounts(a[i], countA);
}
for (int j=0; j<m; j++) {
addCounts(b[j], countB);
}
for (int i=2; i<=MAX; i++) {
int s = std::min(countA[i], countB[i]);
countA[i] -= s;
countB[i] -= s;
}
buildIt(countA, a, n);
buildIt(countB, b, m);

}

inline void init()
{
//Modified sieve of Erathostenes:
//firstFactor[x] will tell us the first prime factor of x.
memset(firstFactor, 0, sizeof(firstFactor));
for (int i=2; i<=MAX; i++) {
if (firstFactor[i] == 0) {
// prime
firstFactor[i] = i;
for (int j=i+i; j <= MAX; j += i) {
if (firstFactor[j] == 0) {
firstFactor[j] = i;
}
}
}
}
}
Email ThisBlogThis!Share to XShare to Facebook
Posted in codeforces, explanation, ouch | No comments
Newer Post Older Post Home

0 comments:

Post a Comment

Subscribe to: Post Comments (Atom)

Popular Posts

  • TopCoder SRM 557 - finally
    SRM 557 Explanation for division 1 Easy and match recap. Explanations for div2 easy and div2 medium. It feels like it has been ages since t...
  • SRM 589 Editorial
    I have finished writing the editorial for TopCoder SRM 589: http://apps.topcoder.com/wiki/display/tc/SRM+589 . As you most likely noticed. L...
  • SRM 590 recap and editorial
    Another week another Topcoder match. Not a great day. I had a bad flu and still do. Div1 500: The one with Xor Given a list of cards with nu...
  • SRM 546: relief
    I figured I should post something about this SRM. I've been very busy these weeks because the semester is ending and I tried to win a t-...
  • SRM 526: The killing wait for results
    While I wait for results, here is my perspective on this algorithm contest. It began with issues, it had to be postponed 15 minutes. TC has ...
  • SRM 554 div1 hard: TheBrickTowerHardDivOne
    Link to problem statement We got infinitely many bricks of dimensions 1x1x1 and C different colors. Count the number of towers of size 2x2...
  • SRM 533: Div1 500 MagicBoard explanation
    Finally solved it. It is a nice problem that is worth explaining in a post. You have a grid/board of at most 50x50 cells. Some cells contain...
  • Member SRM 505: Part 1
    So, let me explain a couple of problems from a Topcoder Member SRM that I wrote and never got an editorial. BTW, it was the last member SRM....
  • ListedLinks 2012-02-10
    Saturday Morning Breakfast Cereal comics: Grace Hopper's ghost That Oracle engineer blog post Oracle would really not like anyone to se...
  • Codeforces "Good bye 2013" round
    So it was a special round for coders of both divisions, problems ranged from the super easy problem A to the super difficult problems E,F,G....

Categories

  • acm
  • algorithm
  • answers
  • arenaplugin
  • badday
  • behindthescenes
  • bugs
  • c++
  • censorship
  • codechef
  • codeforces
  • contests
  • crocchamp
  • editorial
  • editorial.srm
  • embarrassing
  • explanation
  • gcj2013
  • gmp
  • goodday
  • google
  • googlecodejam
  • greed
  • groklaw
  • health
  • html
  • httpseverywhere
  • implementation
  • ipsc
  • ispc
  • java
  • kawigiedit
  • kindagoodday
  • lamebook
  • languages
  • lego
  • listedlinks
  • marathon
  • nasa
  • offtopic
  • ouch
  • postmortem
  • postportem
  • practical
  • probably_not_a_good_tip
  • problemsetting
  • programming
  • python
  • quora
  • rant
  • recap
  • slightlygoodday
  • snippet
  • srm
  • stl
  • strategy
  • swerc
  • tco
  • tco12
  • tco13
  • tco2012
  • tco2013
  • ternarysearch
  • topcoder
  • tricks
  • ubuntu
  • uva
  • vjass
  • vkcup
  • wc3
  • zinc

Blog Archive

  • ►  2014 (1)
    • ►  January (1)
  • ►  2013 (141)
    • ►  December (14)
    • ►  November (8)
    • ►  October (13)
    • ►  September (11)
    • ►  August (14)
    • ►  July (15)
    • ►  June (13)
    • ►  May (13)
    • ►  April (12)
    • ►  March (11)
    • ►  February (11)
    • ►  January (6)
  • ▼  2012 (94)
    • ►  December (5)
    • ►  October (6)
    • ▼  September (8)
      • Surprise test SRM the 25-th (Tomorrow!)
      • Codeforces #140 (Div 1)
      • Learning to find bugs
      • SRM 556 : #@!$%!
      • SRM 554 div1 hard: TheBrickTowerHardDivOne
      • Codeforces #137 (div2) C. Reducing Fractions - update
      • SRM 555: 5555555555555555555555
      • SRM 554
    • ►  August (6)
    • ►  July (3)
    • ►  June (5)
    • ►  May (8)
    • ►  April (10)
    • ►  March (20)
    • ►  February (16)
    • ►  January (7)
  • ►  2011 (51)
    • ►  December (7)
    • ►  November (12)
    • ►  October (5)
    • ►  September (1)
    • ►  August (3)
    • ►  July (4)
    • ►  June (3)
    • ►  May (7)
    • ►  April (3)
    • ►  March (2)
    • ►  February (1)
    • ►  January (3)
  • ►  2010 (9)
    • ►  December (4)
    • ►  October (1)
    • ►  June (1)
    • ►  May (1)
    • ►  January (2)
  • ►  2009 (1)
    • ►  December (1)
Powered by Blogger.

About Me

Unknown
View my complete profile