Saturday, June 16, 2007

Final Indonesia National Contest 2007 :: Problem E - Panda Number

ACM/ICPC Indonesia National Contest 2007

Problem E

The Adventure in Panda Land Part I: Panda Number

Time Limit: 1s


In Panda Land, pandas have their own numeral system to represent a number. Surprisingly, this numeral system is similar to the famous Roman Numerals in our ancient civilization. Although pandas are aware about numeral system, they can not write (imagine how can a panda write!). Instead, they cut and arrange bamboos to form a number.

Decimal Panda Number Required Bamboo
1I1
5V2
10X2
50L2
100C3
500N3
1,000M4
5,000E4
10,000W4
50,000F3
100,000Y3
500,000K3
1,000,000H3
5,000,000T2
10,000,000A3
  These are the production rules of Panda Number:
  • Letters which represent powers-of-ten (I, X, C, M, W, Y, H, A) can be repeated at most three times. The others (V, L, N, E, F, K, T) can not be repeated.
  • If one or more letters are placed after another letter of greater value, add that amount. The letters should be written in descending order from the largest to the least value. For example:
    FXVIII = 50000 + 10 + 5 + 1 + 1 + 1 = 50018
  • If a letter is placed before another letter of greater value, subtract that amount. Only subtract one letter from another. For example:
    XIV = 10 + (5 - 1) = 14
    CIX = 100 + (10 - 1) = 109
    MECIX = (5000 - 1000) + 100 + (10 - 1) = 4109
  • Only powers-of-ten can be used to subtract a value (that is, you can subtract I from V, or X from L, but not V from X (V is not powers-of-ten.)
  • Do not subtract a letter from one that is more than 10 times greater (that is, you can subtract I from X, but not I from L -- there is no such number as IL.)

The aforementioned rules imply that there is exactly one representation in Panda Number for each number in decimal system.

Unlike those Roman Numerals, pandas do recognize zero and negative number (which prove pandas are more advanced than our ancient Romans). To represent a negative number, they add one bamboo as a negative sign in front of the letters. Zero is a special number which doesn't fall into any rules above. To form a zero, pandas need five bamboos.

The number of bamboos needed to form a number is the sum of required bamboos for each letter that appears in that number. For Example:
4108 = 4000+100+8 = (5000-1000)+100+5+1+1+1 = MECVIII (16 bamboos).
4109 = 4000+100+9 = (5000-1000)+100+(10-1) = MECIX (14 bamboos).
-205 = [-], 200+5 = 100+100+ 5 = -CCV (9 bamboos)

Given two numbers A and B, find out how many bamboos needed by panda to form (remember, they can't write) all number between A and B inclusively.

Input

The input begins with a single positive integer T in a line indicating the number of test cases. Each case contains two numbers A and B (-25,000,000 <= A <= B <= 25,000,000) in a line.

Output

For each case, print in a single line the number of needed bamboos to form all numbers between A and B (inclusive).

Sample Input

7
-1 1
4018 4019
-25000000 25000000
-100 -57
-100 0
0 100
43 100

Sample Output

8
28
2121000021
399
778
678
434


Problem Setter: Evan Leonardi


Pembahasan Problem E - Panda Number

Anda diberikan sistem angka untuk Panda yang mirip sistem angka pada Roman. Diperlukan jumlah bambu tertentu untuk membentuk suatu angka. Untuk range A..B (-25 juta <= A < B < 25 juta), anda diminta untuk menghitung berapakah jumlah bambu yang diperlukan untuk membentuk semua angka dari A sampai B? Untuk lebih jelasnya silahkan lihat problem statement diatas.

Menurut pemahaman saya, setiap angka di decimal number system bisa diubah menjadi roman/panda system secara terpisah berdasarkan letak dari significant digit masing-masing angka tersebut.

Contoh:

3      = 3 * 10^0  -> III
30     = 3 * 10^1  -> XXX
300    = 3 * 10^2  -> CCC
3000   = 3 * 10^3  -> MMM
30000  = 3 * 10^4  -> WWW
...

4      = 4 * 10^0  -> IV
40     = 4 * 10^1  -> XL
400    = 4 * 10^2  -> CN
4000   = 4 * 10^3  -> ME
40000  = 4 * 10^4  -> WF
...

8      = 8 * 10^0  -> VIII
80     = 8 * 10^1  -> LXXX
800    = 8 * 10^2  -> NCCC
8000   = 8 * 10^3  -> EMMM
80000  = 8 * 10^4  -> FWWW
...

dan yang lain dan seterusnya

Dari contoh diatas, terlihat pattern:
Sebenarnya I,X,L,C,M,W,Y,H,A itu semua sama saja, yang membedakannya adalah pangkat 10 nya, begitu pula dengan V,L,N,E,F,K,T.
Jadi, format angka 80 itu sama saja dengan angka 80000, hanya saja L diganti F, dan X diganti W. Otomatis kita tinggal membuat tabel:
Untuk pangkat 10 tertentu, apakah simbol yang bersangkutan? atau
Untuk pangkat 10 tertentu, berapa bambu yang dibutuhkan?
Untuk soal ini, kita tidak perlu tahu simbolnya, tapi hanya jumlah bambunya saja. Anda bisa lihat function bamboo(d,p) dibawah untuk menghitung berapa bamboo yang diperlukan untuk digit d dimana digit tersebut ada di posisi 10^p. Contoh:
Untuk menghitung banyak bambu untuk angka 80000 = 8 * 10^4, tinggal panggil bamboo(8,4).

Karena range A, B begitu besar, maka anda perlu mem-precalculate hasil untuk semua range. Ini bisa dilakukan dengan menggunakan dynamic programming (membuat tabel dp) yang meng-akumulasi jumlah bamboo dari 1 sampai n. Untuk menghitung jumlah bambu dari range A sampai B, anda tinggal menghitung dp[B] - dp[A-1] dimana A dan B harus positive. Kalau A atau B adalah negative atau nol, maka diperlukan sedikit if-else. Lihat dibawah untuk semua kemungkinan A dan B beserta perhitungannya.

Ada cara untuk menghitung akumulasi bambu dari 1..n on-the-fly hanya dalam O(banyak nya digit di input ^ 2). Saya diberi tahu cara ini oleh Stephen Kohar dari tim NoMoreAC. Caranya adalah (nanti saya jelaskan), kalian coba liat source code nya dulu dech dibawah (dengan nama panda-on-the-fly.c). Function bamboo dan main function tidak berubah sama sekali, yang berubah adalah dp[i] tidak lagi di-precalculate, tapi dihitung on-the-fly dp(i).

#include <stdio.h>
#include <math.h>

#define MAXN 25000000

int need[8][2] = { {1,2}, {2,2}, {3,3}, {4,4}, {4,3}, {3,3}, {3,2}, {3,0} };

// berapa bamboo yang diperlukan untuk digit d dimana digit tersebut ada di 10^p
int bamboo(int d, int p){
    switch (d){
        case 0: return 0; // special case
        case 1: return 1 * need[p][0] + 0 * need[p][1]; // I
        case 2: return 2 * need[p][0] + 0 * need[p][1]; // II
        case 3: return 3 * need[p][0] + 0 * need[p][1]; // III
        case 4: return 1 * need[p][0] + 1 * need[p][1]; // IV
        case 5: return 0 * need[p][0] + 1 * need[p][1]; // V
        case 6: return 1 * need[p][0] + 1 * need[p][1]; // VI
        case 7: return 2 * need[p][0] + 1 * need[p][1]; // VII
        case 8: return 3 * need[p][0] + 1 * need[p][1]; // VIII
        case 9: return 1 * need[p][0] + 0 * need[p][1] + 
                       1 * need[p+1][0] + 0 * need[p+1][1]; // IX
    }
}

int dp[MAXN+1]; // dp[i] adalah jumlah bamboo untuk membentuk angka angka dari 1 sampai i

void precalculate(){
    int i,j,k,p,base,need;

    // precalculate table dp untuk menghindari time limit
    // perhitungan DP ini memang agak sulit dijelaskan maupun dimengerti
    // tetapi dengan pengalaman dan latihan, anda akan bisa memahaminya :D
    dp[0] = 0;
    for (p=0,i=1; p<9; p++,i*=10){
        for (j=0; j<10; j++){
            if (i*j > MAXN) break;
            base = i*j;
            need = bamboo(j,p);
            for (k=0; k<i; k++){
                if (base+k > MAXN) break;
                dp[base+k] = need + dp[k];
            }
        }
    }

    for (i=1; i<=MAXN; i++) dp[i] += dp[i-1];               // akumulasi
}

int main(){
    int T,A,B;

    precalculate();

    scanf("%d",&T);
    while (T--){
        scanf("%d %d",&A,&B);
        if (A<0){
            A = abs(A);
            if (B<0){
                B = abs(B);
                printf("%d\n", dp[A] - dp[B-1] + (A-B+1));  // A <= B < 0
            } else {
                printf("%d\n", A + dp[A] + 5 + dp[B]);      // A < 0 <= B
            }
        } else { // 0 <= A <= B
            if (A==0){
                printf("%d\n", dp[B] + 5);                  // 0 == A <= B
            } else {
                printf("%d\n", dp[B] - dp[A-1]);            // 0 < A <= B
            }
        }
    }
}
#include <stdio.h>
#include <math.h>

#define MAXN 25000000

int need[8][2] = { {1,2}, {2,2}, {3,3}, {4,4}, {4,3}, {3,3}, {3,2}, {3,0} };

// berapa bamboo yang diperlukan untuk digit d dimana digit tersebut ada di 10^p
int bamboo(int d, int p){
    switch (d){
        case 0: return 0; // special case
        case 1: return 1 * need[p][0] + 0 * need[p][1]; // I
        case 2: return 2 * need[p][0] + 0 * need[p][1]; // II
        case 3: return 3 * need[p][0] + 0 * need[p][1]; // III
        case 4: return 1 * need[p][0] + 1 * need[p][1]; // IV
        case 5: return 0 * need[p][0] + 1 * need[p][1]; // V
        case 6: return 1 * need[p][0] + 1 * need[p][1]; // VI
        case 7: return 2 * need[p][0] + 1 * need[p][1]; // VII
        case 8: return 3 * need[p][0] + 1 * need[p][1]; // VIII
        case 9: return 1 * need[p][0] + 0 * need[p][1] + 
                       1 * need[p+1][0] + 0 * need[p+1][1]; // IX
    }
}

int dp(int n){
    int p=0, digit=n, power=1, remaining=0, result=0, i;

    if (n<=0) return 0;
    while (digit>9) power *= 10, digit /= 10,  p++;
    remaining = n - digit*power;
    result = dp(remaining) + bamboo(digit,p) * (remaining+1) + dp(power-1) * digit;
    for (i=1; i<digit; i++) result += bamboo(i,p) * power;
    return result;
}

int main(){
    int T,A,B;

    scanf("%d",&T);
    while (T--){
        scanf("%d %d",&A,&B);
        if (A<0){
            A = abs(A);
            if (B<0){
                B = abs(B);
                printf("%d\n", dp(A) - dp(B-1) + (A-B+1));  // A <= B < 0
            } else {
                printf("%d\n", A + dp(A) + 5 + dp(B));        // A < 0 <= B
            }
        } else { // 0 <= A <= B
            if (A==0){
                printf("%d\n", dp(B) + 5);                    // A==0, A <= B
            } else {
                printf("%d\n", dp(B) - dp(A-1));            // 0 < A <= B
            }
        }
    }
}

Kembali ke halaman utama

No comments:

Post a Comment