USACO FEB09 Problem 'cruel1' Analysis

by Rob Kolstad

This is a standard multiple-precision or 'bigint' task. The goal is to write a multiplication routine that can multiply a small integer (normal-sized, in some sense) and a 'bigint', an integer much larger than can be stored in 32 or 64 bits.

The general technique for this involves storing a large number as a sequence of, say, nine digit numbers. Multiplication is performed just the same as manual multiplication is, except that instead of one digit at a time, it's nine digits at a time. The digits that won't fit are carried over to the next word.

A cleverer technique for calculating large powers involves a full bigint x bigint routine and working how to multiply partial products to reduce the number of multiplications (e.g., 2^64 = (2^32)^2 = ((2^16)^2)^2 = ((((2^8)^2)^2)^2 = ((((((2^4)^2)^2)^2)^2 = (((((((2^2)^2)^2)^2)^2)^2 -- reducing the number of multiplications from 64 to 6 -- a 10x reduction).

The only real trick is printing leading zeroes on every number except the first one. My easy solution is below.

#define MOD 100000000           /* 10^9 might have been a better choice */

int ans[15000];
char out[1000020];
int maxans = 0;
int main() {
     FILE *fin = fopen ("cruel1.in", "r");
     FILE *fout = fopen ("cruel1.out", "w");
     int n, p, i, j, k, carry;
     char *outp;
     long long partial;
     fscanf (fin, "%d %d", &n, &p);
     ans[0] = 1;
     for (k = 0; k < p; k++) {
        /* multiply 'ans' by n */
        carry = 0;
        for (i = 0; i <= maxans || carry; i++) {
            partial = n * (long long) ans[i] + carry;
            if (partial >= MOD) {
                ans[i] = partial % MOD;
                carry = partial / MOD;
            } else {
                ans[i] = partial;
                carry = 0;
            }
            if (ans[i] && i > maxans) maxans = i;
        }
     }
        /* print answer */
     outp = out;
     for (i = maxans; i>=0; i--) {
        if (i == maxans) sprintf (outp, "%d", ans[i]);
        else             sprintf (outp, "%08.8d", ans[i]);
        while (*outp) outp++;
     }
     for (i = 0; out[i]; i+= 70)
        fprintf(fout, "%.70s\n", &out[i]);
     exit (0);
}