20111031

ACM 10340 All in All

找subsequence。
直接做。

又是一題測資機車題,
RE的話請把array設成1000000!

/* ACM 10340 All in All
 * mythnc
 * 2011/10/31 14:33:05   
 * run time: 0.008
 */
#include <stdio.h>
 
#define MAXARY 1000000
#define YES    1
#define NO     0

int form(char *, char *);
 
int main(void)
{
    char s[MAXARY], t[MAXARY];
 
    while (scanf("%s %s", s, t) == 2)
        if (form(s, t) == YES)
            printf("Yes\n");
        else
            printf("No\n");
    return 0;
}
 
/* form: judge s is a subsequence of t or not,
 * return the judgement yes or no */
int form(char *s, char *t)
{
    int i, j;
 
    for (i = j = 0; t[j] != '\0' && s[i] != '\0'; j++)
        if (s[i] == t[j])
            i++;
 
    if (s[i] == '\0')
        return YES;
 
    return NO;
}

ACM 374 Big Mod

算mod,但慢慢來是會TL的。
所以要想個比較快的方法。

因為mod的值一定會重複,
所以就把mod值紀錄起來,
每次有新mod值進來就加進去,
如果mod已經被紀錄了,表示重複,
輸出紀錄值即可。

/* ACM 374 Big Mod
 * mythnc
 * 2011/10/31 11:57:08   
 * run time: 0.02
 */
#include <stdio.h>

#define MAXARY 47000
#define IN     1
#define OUT    0

int add(int *, int, int *);

int main(void)
{
    int b, p, m, tmp, tag, count;
    int rec[MAXARY];

    while (scanf("%d %d %d", &b, &p, &m) == 3) {
        count = 0;
        tag = OUT;
        for (rec[count++] = tmp = b %= m; --p;) {
            b *= tmp;
            if (b > m)
                b %= m;
            if (add(rec, b, &count) == IN) {
                tag = IN;
                break;
            }
        }

        if (tag == IN) {
            tmp = p % count - 1;
            /* can be divide */
            if (tmp < 0)
                tmp = count - 1;
            printf("%d\n", rec[tmp]);
            continue;
        }

        printf("%d\n", b);
    }
    return 0;
}

/* add: save mod number in rec,
 * if number is already in rec,
 * return IN,
 * else save it return OUT */
int add(int *rec, int b, int *n)
{
    int i;

    for (i = 0; i < *n; i++)
        if (rec[i] == b)
            return IN;

    rec[(*n)++] = b;
    return OUT;
}

20111030

ACM 483 Word Scramble

直接做。

/* ACM 483 Word Scramble
 * mythnc
 * 2011/10/30 19:30:39   
 * run time: 0.008
 */
#include <stdio.h>
#include <string.h>
 
#define MAXARY 1000
 
int main(void)
{
    char s[MAXARY];
    char c;
    int i;
 
    while (scanf("%s%c", s, &c) == 2) {
        for (i = strlen(s) - 1; i > -1; i--)
            printf("%c", s[i]);
        putchar(c);
    }
    return 0;
}

ACM 424 Integer Inquiry

大數加法。
第一次寫大數,很好玩 @@。

原來加法不用一次一次算進位,
可以最後再一口氣算進位,有趣!

/* ACM 424 Integer Inquiry
 * mythnc
 * 2011/10/30 18:43:44   
 * run time: 0.004
 */
#include <stdio.h>
#include <string.h>

#define MAXARY 105

int addbig(int *, char *, int);
void printout(int *, int);

int main(void)
{
    char tmp[MAXARY];
    int big[MAXARY] = { 0 };
    int len, count;

    len = 0;
    while (scanf("%s", tmp)) {
        if (tmp[0] == '0' && tmp[1] == '\0') {
            printout(big, len);
            return 0;
        }
        count = addbig(big, tmp, len);
        if (len < count)
            len = count;
    }
}

/* addbig: add big number, return it's length */
int addbig(int *big, char *tmp, int len)
{
    int i, count;

    for (count = 0, i = strlen(tmp) - 1; i > -1; i--)
        big[count++] += tmp[i] - '0';

    /* carry */
    if (count < len)
        count = len;
    for (i = 0; i < count; i++) {
        big[i + 1] += big[i] / 10;
        big[i] %= 10;
    }

    if (big[i] != 0)
        return count + 1;
    return count;
}

/* printout: print out big number */
void printout(int *big, int n)
{
    int i;

    for (i = n - 1; i > - 1; i--)
        printf("%d", big[i]);
    printf("\n");
}

20111029

ACM 369 Combinations

WA無限次……
因為我忘記做gcd惹 @_@。

題目有說不會超過32-bit,所以用int即可。
排列公式把分母(N - M)!或是M!與分子化簡。
變成分子為(N - M + 1) * (N - M + 2) * ... * N
分母為1 * 2 * 3 * ... * M。

因為答案一定是整數,所以分母一定可以被分子化簡,
注意!
如果遇到不能化簡,要找gcd化簡,
例如:15 7,這種組合就要找gcd。
沒找gcd直接化簡就gg了。 @_@。

N - M跟M,較小的留下來,大的做化簡即可。

/* ACM 369 Combinations
 * mythnc
 * 2011/10/29 16:51:07   
 * run time: 0.008
 */
#include <stdio.h>

#define MAXARY 50

int com(int, int);
int gcd(int, int);

int main(void)
{
    int m, n;

    while (scanf("%d %d", &n, &m)) {
        if (n == 0 && m == 0)
            return 0;
        printf("%d things taken %d at a time is %d exactly.\n"
               , n, m, com(n, m));
    }
}

/* com: return the combined times */
int com(int n, int m)
{
    int i, j, factor, tmp;
    int num[MAXARY];

    if (m == n || m == 0)
        return 1;

    if (m > n - m)
        m = n - m;
    /* init */
    for (i = 0; i < m; i++)
        num[i] = n - m + 1 + i;
    /* simplify */
    for (i = m; i > 1; i--) {
        tmp = i;
        for (j = 0; j < m; j++) {
            if (num[j] % tmp == 0) {
                num[j] /= tmp;
                break;
            }

            factor = gcd(tmp, num[j]);
            if (factor > 1) {
                tmp /= factor;
                num[j] /= factor;
            }
        }
    }
    /* product */
    for (i = 1; i < m; i++)
        num[0] *= num[i];

    return num[0];
}

/* gcd: return the gcd of a and b */
int gcd(int a, int b)
{
    while ((a %= b) && (b %= a))
        ;

    return a + b;
}

ACM 382 Perfection

算因素和。
算到根號n即可。
根號n一次,其他相對應的兩次。

sub = n - sum;放在if外面可以快0.004秒耶 -_-a

/* ACM 382 Perfection
 * mythnc
 * 2012/03/31 21:38:57   
 * run time: 0.004
 */
#include <stdio.h>
 
typedef enum {PERFECT, ABUNDANT, DEFICIENT} number;

number sumfactor(int);

int main(void)
{
    int n;
    char *num[3] = {"PERFECT", "ABUNDANT", "DEFICIENT"};

    printf("PERFECTION OUTPUT\n");
    while (scanf("%d", &n) && n != 0)
        printf("%5d  %s\n", n, num[sumfactor(n)]);

    printf("END OF OUTPUT\n");

    return 0;
}

/* sumfactor: sum the factor of n,
 * and return correspond symbol
 * of n - sum */
number sumfactor(int n)
{
    int i, sum, sub;

    if (n == 1)
        return DEFICIENT;

    for (sum = 1, i = 2; i * i <= n; i++)
        if (n % i == 0) {
            sum += i;
            if (n / i != i)
                sum += n / i;
        }

    sub = n - sum;
    if (sub > 0)
        return DEFICIENT;
    else if (sub == 0)
        return PERFECT;
    else
        return ABUNDANT;
}

20111028

USACO Milking Cows

奇怪看別人處理data都是一次吃完再handle,
我習慣能一個一個handle就先handle。
不過這樣coding似乎也沒比較快,而且有點複雜……
sort以後用內建qsort好了 @_@。

一次吃一行資料,
跟已經吃進來的資料做比較:
吃進來的資料,
可能start在某個farmer中,
或end在某個farmer中,
或是被某個farmer包含,
或包含某個farmer。
光吃資料就夠複雜了吧 -.-

之後做sort,就可以輸出最大milk times,
與idle times。

看來一次先吃完所有資料就不會這麼麻煩……
教學文也說這是complete search。

/*
ID: mythnc2
LANG: C
TASK: milk2
Milking Cows
2011/10/28 14:44:22   
*/
#include <stdio.h>

#define MAXN 5000
#define BEGIN   0
#define END     1
#define SWAP(x, y, t)  (t = x, x = y, y = t)

void addframer(int (*)[], int *, int *);
void maxf(int (*)[], int, int *, int *);
void sort(int (*)[], int *);

int main (void)
{
    FILE *fin, *fout;
    int farmer[MAXN][2];
    int tmp[2];
    int n, number, maxmilk, maxidle;

    fin = fopen("milk2.in", "r");
    fout = fopen("milk2.out", "w");

    fscanf(fin, "%d", &n);
    for (number = 0; n; n--) {
        fscanf(fin, "%d %d", tmp, tmp + 1);
        addframer(farmer, tmp, &number);
    }

    sort(farmer, &number);
    maxf(farmer, number, &maxmilk, &maxidle);

    fprintf(fout, "%d %d\n", maxmilk, maxidle);

    return 0;
}

/* adframer: if tmp in farmer, update it,
 * if not in farmer, add tmp */
void addframer(int (*farmer)[2], int *tmp, int *n)
{
    int i;

    for (i = 0; i < *n; i++) {
        /* 0 0 condition */
        if (farmer[i][BEGIN] == 0 && farmer[i][END] == 0)
            continue;

        /* tmp contain farmer[i] */
        if (tmp[BEGIN] < farmer[i][BEGIN]
            && tmp[END] > farmer[i][END]) {
            farmer[i][BEGIN] = farmer[i][END] = 0;
            continue;
        }
        /* farmer[i] contains tmp */
        else if (farmer[i][BEGIN] <= tmp[BEGIN]
                 && farmer[i][END] >= tmp[END])
            return;

        /* update: farmer[i] contains tmp[BEGIN] */
        if (farmer[i][BEGIN] < tmp[BEGIN]
            && tmp[BEGIN] <= farmer[i][END]) {
            tmp[BEGIN] = farmer[i][BEGIN];
            farmer[i][BEGIN] = farmer[i][END] = 0;
            /* start from head again */
            i = -1;
        }
        /* update: farmer[i] contains tmp[END] */
        else if (farmer[i][BEGIN] <= tmp[END]
            && tmp[END] < farmer[i][END]) {
            tmp[END] = farmer[i][END];
            farmer[i][BEGIN] = farmer[i][END] = 0;
            /* start from head again */
            i = -1;
        }
    }

    (*n)++;
    farmer[i][BEGIN] = tmp[BEGIN];
    farmer[i][END] = tmp[END];
}

/* maxf: find the maxmilk and maxidle times */
void maxf(int (*farmer)[2], int n, int *milk, int *idle)
{
    int i;

    if (n == 1) {
        *milk = farmer[0][END] - farmer[0][BEGIN];
        *idle = 0;
        return;
    }

    for (*idle = *milk = i = 0; i < n; i++) {
        if (*milk < farmer[i][END] - farmer[i][BEGIN])
            *milk = farmer[i][END] - farmer[i][BEGIN];
        if (i < n - 1 && *idle < farmer[i][BEGIN] - farmer[i + 1][END])
            *idle = farmer[i][BEGIN] - farmer[i + 1][END];
    }
}

/* sort: selection sort from high to low does not contain 0 */
void sort(int (*f)[2], int *n)
{
    int i, j, max, tmp;

    for (i = 0; i < *n - 1; i++) {
        for (max = j = i; j < *n; j++)
            if (f[max][BEGIN] < f[j][BEGIN])
                max = j;
        if (max != i) {
            SWAP(f[max][BEGIN], f[i][BEGIN], tmp);
            SWAP(f[max][END], f[i][END], tmp);
        }
    }

    /* delete 0 0 */
    while (f[*n - 1][BEGIN] == 0 && f[*n - 1][END] == 0)
        (*n)--;
}

ACM 10110 Light, more light

TL TL TL TL zzzz。
機車啊,害我想弄一個array把1到65535的次方
放進去。
觀察法:
   1 2 3 4 5 6 7 8 9 10  (燈泡)
1  y y y y y y y y y y 
2  y n y n y n y n y n
3  y n n n y y y n n n
4  y n n y y y y y n n
5  y n n y n y y y n y
6  y n n y n n y y n y
7  y n n y n n n y n y
8  y n n y n n n n n y
9  y n n y n n n n y y
10 y n n y n n n n y n
(次數)
row是次數,
column是燈泡。
求第n次,第n個燈泡是亮還是不亮。
所以1到10的解分別是
1 2 3 4 5 6 7 8 9 10
y n n y n n n n y n
想法很簡單,
判斷第i個燈泡是否有因數。
沒因數 => 質數 => 不亮,
有因數 => 合數,
合數兩種情況,
(1)有單數個因素 => 亮
(2)有雙數個因素 => 不亮

以10為例,
1x10 = 2x5 = 5x2 = 10x1 = 10
1, 2, 5, 10所以不亮。
之後簡化,算到根號n就好,
(因為合數必然是兩個數相乘,
兩者之一必有一數大於等於根號n,另一數小於等於根號n)
所以5, 10都可以去掉,
1必然是因素,也去掉。
剩2,單個,但2表示2x5 = 5x2 = 10
說是單個,要乘以2,實際上是雙數,
唯一一種例外情況,以16為例,
2, 4,兩個,2x8 = 8x2 = 16
4x4 = 4x4 = 16,只能算一個。
得到結論:若根號n為n的因素,只能算一個。
這種情況,就是亮(單數個因素)

再往下推,
所以不管因素有幾個,
如果根號n是因素,那必定是單數個因素,
根號n不是因素,必定是雙數個因數。
這樣就很簡單了,
只要判斷根號n是否為n的因素,
就知道第n個燈泡會不會亮。

但是慢慢算還是會TL的(我就是),
所以要嘛用一個超大的array事先算好1~65535的次方數,
要嘛就用math.h函式庫的sqrt()幫忙算根號n。
機車測資啊……
i用unsigned就好,long long會快一點。

/* ACM 10110
 * mythnc
 * 2011/10/28 11:20:00   
 * run time: 0.032
 */
#include <stdio.h>
#include <math.h>

#define YES 1
#define  NO 0

int factor(double n);

int main(void)
{
    double n;

    while (scanf("%lf", &n)) {
        if (n == 0)
            return 0;
        if (n == 1 || factor(n) == YES)
            printf("yes\n");
        else
            printf("no\n");
    }
}

/* factor: calculate the square root of n is integer or not
 * if is return 1 else return 0 */
int factor(double n)
{
    long long i;

    i = sqrt(n);
    if (i * i == n)
        return YES;
    else
        return NO;
}

ACM 10696 f91

做遞迴可求解。
但不要真的用遞迴去解。
由f91(N) = f91(f91(N+11)),
可以發現,當N <= 100時,
會一直做+11的動作,再call f91()做判斷,
直到N = 101,此時輸出91。
所以N < 101就是輸出91,
N >= 101時輸出N - 11。

/* ACM 10696 f91
 * mythnc
 * 2011/10/28 10:17:55   
 * run time: 0.108
 */
#include <stdio.h>
 
int f91(int);
 
int main(void)
{
    int n;
 
    while (scanf("%d", &n)) {
        if (n == 0)
            return 0;
        printf("f91(%d) = %d\n", n, f91(n));
    }
}
 
/* f91: f91 function */
int f91(int n)
{
    if (n > 100)
        return n - 10;
    else
        return 91;
}

20111027

USACO Broken Necklace

寫得很爛,根本不知道可以怎麼做,囧。
只好硬幹。寫到快起肖,悲劇。

先找每組珠子的數目數,之後存起來,
接著找最大的珠子數,
再檢查該珠子的兩側(因為環狀),
是否有算錯,
例如bwrwb可能是1 3 1或2 1 2。
沒錯的話就可以輸出。

/*
ID: mythnc2
LANG: C
TASK: Beads
Broken Necklace
2011/10/27 11:41:05   
*/
#include <stdio.h>
#include <string.h>

#define MAXARY 360

typedef struct record{
    int count;
    char *head, *tail;
} Record;

int firstlen(char *);
void movefirst(char *, int);
char *len(char *, Record *, int *);
int backward(char *);
int maxvalue(Record *, int);
int pairs(Record *, Record);
int reverse(char *, char *);

int main(void)
{
    FILE *fin, *fout;
    char bead[MAXARY];
    char *move;
    Record rec[MAXARY];
    int n, i, step;

    fin = fopen("beads.in", "r");
    fout = fopen("beads.out", "w");
    
    fscanf(fin, "%d", &n);
    fscanf(fin, "%s", bead);

    if ((i = firstlen(bead)) == n) {  /* one color */
        fprintf(fout, "%d\n", i);
        return 0;
    }
    else
        movefirst(bead, i);

    for (move = bead, i = 0; *move; i++) {
        move = len(move, &rec[i], &step);
        if (step)
            i++;
    }

    if (i < 3)
        fprintf(fout, "%d\n", rec[0].count + rec[1].count);
    else
        fprintf(fout, "%d\n", maxvalue(rec, i));

    return 0;
}

/* firstlen: count the first length
 * also use this function to count w length */
int firstlen(char *bead)
{
    int i;

    i = 0;
    /* if first char is w, skip over it */
    while (bead[i] == 'w')
        i++;
    if (bead[i] == '\0')   /* all beads is w color */
        return i;

    if (bead[i] == 'b')
        while (bead[i] == 'b' || bead[i] == 'w')
            i++;
    else
        while (bead[i] == 'r' || bead[i] == 'w')
            i++;
    return i;
}

/* movefirst: rearrange string bead,
 * move the first len to last */
void movefirst(char *bead, int n)
{
    int i;
    char tmp[n];

    strncpy(tmp, bead, n);
    for (i = 0; bead[i + n] != '\0'; i++)
        bead[i] = bead[i + n];
    bead[i] = '\0';
    strncat(bead, tmp, n);
}

/* len: count the len of each color bead
 * and return the position after count */
char *len(char *move, Record *rec, int *step)
{
    int wcount;
    char *w;

    wcount = rec->count = *step = 0;
    rec->head = move;
    if (*move == 'b')
        while (*move == 'b' || *move == 'w') {
            if (*move == 'w' && wcount == 0) {
                wcount = firstlen(move);
                w = move;
            }
            rec->count++;
            move++;
        }
    else  /* color r */
        while (*move == 'r' || *move == 'w') {
            if (*move == 'w' && wcount == 0) {
                wcount = firstlen(move);
                w = move;
            }
            rec->count++;
            move++;
        }

    if (wcount > rec->count) {
        *step = 1;
        rec->count -= backward(move); /* corrected count */
        move = w + wcount;            /* corrected position */
        rec->tail = w;
        (++rec)->count = wcount;      /* the next count value */
        rec->head = w;
    }
    rec->tail = move;
    return move;
}

/* backward: backward pointer to find previous color,
 * which is not w color return the backward steps */
int backward(char *back)
{
    int count;

    count = 0;
    while (*--back == 'w')
        count++;

    return count;
}

/* maxvalue: find the max element
 * if max is not only one, judge them sequentially
 * return the biggest count of this element 
 * and its adjacence */
int maxvalue(Record *rec, int n)
{
    int i, max, count, tmp;
    int index[MAXARY];

    for (max = i = 0; i < n; i++)
        if (rec[max].count < rec[i].count)
            max = i;
    /* find the number of max */
    for (count = i = 0; i < n; i++)
        if (rec[max].count == rec[i].count)
            index[count++] = i;

    for (max = i = 0; i < count; i++) {
        if (index[i] == 1)
            tmp = pairs(&rec[n - 1], rec[2]) + rec[0].count;
        else if (index[i] == 0)
            tmp = pairs(&rec[n - 2], rec[1]) + rec[0].count;
        else if (index[i] == n - 1)
            tmp = pairs(&rec[n - 3], rec[0]) + rec[n - 1].count;
        else
            tmp = pairs(&rec[index[i] - 2], rec[index[i] + 1])
                   + rec[index[i]].count;
        if (tmp > max)
            max = tmp;
    }
    return max;
}

/* pairs: recalculate pre and next len
 * return the largest */
int pairs(Record *pre, Record next)
{
    int pv, nv;

    nv = firstlen(next.head);
    pv = reverse(pre->head, pre[1].tail);

    return nv > pv ? nv : pv;
}

/* reverse: reverse the beads before max,
 * recalulate it's len and return it */
int reverse(char *head, char *tail)
{
    char seq[MAXARY];
    char *move;
    int i;

    for (i = 0, move = tail - 1; move > head - 1; move--)
        seq[i++] = *move;
    seq[i] = '\0';

    return firstlen(seq);
}

ACM 575 Skew Binary

先反轉string,
再加總,
最後output即可。

/* ACM 575
 * mythnc
 * 2011/10/27 09:21:55   
 * run time: 0.004
 */
#include <stdio.h>
 
#define MAXARY 35
 
void reverse(char *s);
 
int main(void)
{
    int sum, i, k; 
    char seq[MAXARY];
 
    while (scanf("%s", seq)) {
        if (seq[0] == '0' && seq[1] == '\0')
            return 0;
        reverse(seq);
        for (sum = i = 0, k = 1; seq[i] != '\0'; i++) {
            k *= 2;
            sum += (seq[i] - '0') * (k - 1);
        }
        printf("%d\n", sum);
    }
}
 
 
/* reverse: reverse seq s */
void reverse(char *s)
{
    int i, j;
    char tmp;
 
    for (j = 0; s[j] != '\0'; j++)
        ;
    for (j--, i = 0; i < j; i++, j--) {
        tmp = s[i];
        s[i] = s[j];
        s[j] = tmp;
    }
}

ACM 10783 Odd Sum

奇數加總。
a, b可能為偶數要注意。
? :中間有放東西比沒放快0.004秒,
真妙。

/* ACM 10783
 * mythnc
 * 2011/10/27 08:42:49   
 * run time: 0.004
 */
#include <stdio.h>

int main(void)
{
    int a, b, set;

    scanf("%*d");
    set = 0;
    while(scanf("%d %d", &a, &b) == 2) {
        a % 2 ? a : a++;  /* if a is even */
        b % 2 ? b : b--;  /* if b is even */
        printf("Case %d: %d\n", ++set, ((b - a) / 2 + 1) * (b + a) / 2);
    }
    return 0;
}

20111026

USACO Friday the Thirteenth

就只是個數饅頭……
除了第一年的1月另外計算,
往後的1月13號都是去年的12月13號 + 31(DEC)。

/*
ID: mythnc2
LANG: C
TASK: friday
2011/10/26 19:37:31   
*/
#include <stdio.h>
 
#define MONTHS      12
#define FIRSTYEAR 1900
#define WEEK         7
 
int leap(int);
 
int main (void)
{
    FILE *fin, *fout;
    int n, i, j, day;
    int thirteen[WEEK] = { 0 };
    int month[MONTHS] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    enum Months {JAN, FEB};
 
    fin = fopen("friday.in", "r");
    fout = fopen("friday.out", "w");
 
    fscanf(fin, "%d", &n);
 
    /* simplify months */
    for (i = 0; i < MONTHS; i++)
        month[i] %= WEEK;
 
    for (day = 1 + 12, i = 0; i < n; i++) {
        if (i > 0)       /* DEC/13 + 31 = JAN/13 */
            day += month[j];
        day %= WEEK;
        thirteen[day]++;
        for (j = JAN; j < MONTHS - 1; j++) {
            day += month[j];
            if (j == FEB && leap(i))
                day++;
            day %= WEEK;
            thirteen[day]++;
        }
    }
    /* printout: from sat to fri */
    fprintf(fout, "%d", thirteen[WEEK - 1]);
    for (i = 0; i < WEEK - 1; i++)
        fprintf(fout, " %d", thirteen[i]);
    fprintf(fout, "\n");
    return 0;
}
 
/* leap: calculate the year is a leap year or not
 * return 1 if is, 0 if is not */
int leap(int i)
{
    int year;
 
    year = FIRSTYEAR + i;
    return year % 4 == 0 && year % 100 != 0
           || year % 400 == 0;
}

ACM 10189 Minesweeper

兩種方法。
第一種,計算.旁邊有幾顆地雷,
可求.的數字。
第二種,每出現一顆地雷,
地雷四周八個方位各+1。
我用第二種寫法,
感覺第一種比較好實作……

要注意'\0'也算一個字元,
所以column最大值是101。
害我吃了幾次WA -_-。

/* ACM 10189 Minesweeper
 * mythnc
 * 2011/11/29 15:25:38   
 * version 2
 * run time: 0.016
 */
#include <stdio.h>

#define MAXLEN 100
/* if position (x, y) is not '*' */
#define NOTSTAR(f, x, y) if (f[x][y] != '*') f[x][y]++

void dtoz(char (*)[]);
void findstar(char (*)[]);
void add(char (*)[], int, int);

int row, col;

int main(void)
{
    char field[MAXLEN][MAXLEN + 1];
    int i, set;

    set = 0;
    while (scanf("%d %d", &row, &col) == 2) {
        if (row == 0 && col== 0)
            return 0;

        for (i = 0; i < row; i++)
            scanf("%s", field[i]);

        dtoz(field);
        findstar(field);
        /* output */
        if (set > 0)
            printf("\n");
        printf("Field #%d:\n", ++set);
        for (i = 0; i < row; i++)
            printf("%s\n", field[i]);
    }
}

/* dtoz: change dot to '0' */
void dtoz(char (*field)[MAXLEN + 1])
{
    int i, j;

    for (i = 0; i < row; i++)
        for (j = 0; j < col; j++)
            if (field[i][j] == '.')
                field[i][j] = '0';
}

/* findstar: find the position of '*' */
void findstar(char (*f)[MAXLEN + 1])
{
    int i, j;

    for (i = 0; i < row; i++)
        for (j = 0; j < col; j++)
            if (f[i][j] == '*')
                add(f, i, j);
}

/* position: add one to the fields surround of '*' */
void add(char (*f)[MAXLEN + 1], int i, int j)
{
    int mover[] = {1, 1, 1, 0, -1, -1, -1, 0};
    int movec[] = {-1, 0, 1, 1, 1, 0, -1, -1};
    int k, x, y;

    for (k = 0; k < 8; k++) {
        x = i + mover[k];
        y = j + movec[k];
        if (x >= 0 && x < row && y >= 0 && y < col)
            NOTSTAR(f, x, y);
    }
}

ACM 119 Greedy Gift Givers

題目同USACO Greedy Gift Givers
但是同樣code一直RE RE RE啊啊啊啊~~~!!
下次RE第一件事就是檢查除號跟%分母是否為0。
看來ACM的測資機車多了。

/* ACM 119
 * mythnc
 * 2011/10/25 18:37:46   
 * run time: 0.004
 * same as USACO Greedy Gift Givers (gift1.c)
 */
#include <stdio.h>
#include <string.h>

#define LEN   20
#define N     10

typedef struct group {
    char name[LEN + 1];
    int money;
} People;

int findname(People *, char *);
void eatname(int);
void printout(People *, int);

int main(void)
{
    int n, i, j, k, money, ntake, line;
    char tmp[LEN + 1];
    People person[N];

    line = 0;
    while (scanf("%d", &n) != EOF) {
        for (i = 0; i < n; i++) {
            scanf("%s", person[i].name);
            person[i].money = 0;    /* init */
        }

        for (i = 0; i < n; i++) {
            scanf("%s %d %d", tmp, &money, &ntake);
            if (money == 0 || ntake == 0) {        /* haven't to give money */
                if (ntake > 0)
                    eatname(ntake);
                continue;
            }

            j = findname(person, tmp);             /* the giver name */
            /* giver: the money giver have to pay */
            person[j].money += money % ntake - money;
            for (j = 0; j < ntake; j++) {
                scanf("%s", tmp);
                k = findname(person, tmp);         /* the taker name */
                /* taker: the money taker get */
                person[k].money += money / ntake;
            }
        }
        /* output */
        if (line == 1)
            printf("\n");
        printout(person, n);
        line = 1;
    }
    return 0;
}

/* findname: find the tmp name in person,
 * return the index of that name */
int findname(People *person, char *tmp)
{
    int i;

    for (i = 0; ; i++)
        if (strcmp(person[i].name, tmp) == 0)
            return i;
}

/* eatname: eat name token */
void eatname(int n)
{
    while (n--)
        scanf("%*s");
}

/* printout: print out the results */
void printout(People *person, int n)
{
    int i;

    for (i = 0; i < n; i++)
        printf("%s %d\n", person[i].name, person[i].money);
}

ACM 10082 WERTYU

做mapping。
一開始很蠢的想寫一個switch做1 to 1 mapping,
後來想到分成4行,每行就可以做1 to 1 mapping,
但覺得還要再4選1好慢。
其實就把4行當1行,再寫一個mapping即可。
我好蠢。 -_-

/* ACM 10082
 * mythnc
 * 2011/10/26 11:11:29   
 * run time: 0.004
 */
#include <stdio.h>
#include <string.h>
 
void mapping(int c);
 
int main(void)
{
    int c;
 
    while ((c = getchar()) != EOF)
        mapping(c);
    return 0;
}
 
/* mapping: mapping the wrong typing to correct typing */
void mapping(int c)
{
    char key[] = "=-0987654321`\\][POIUYTREWQ';LKJHGFDSA/.,MNBVCXZ";
    char map[256];
    int i;
 
    for (i = 0; i < strlen(key); i++)
        map[key[i]] = key[i + 1];
    if (c == ' ' || c == '\n')
        putchar(c);
    else
        putchar(map[c]);
 
}

ACM 299 Train Swapping

ACM10327
資料量很小,bubble比merge還快。
cocktail跟bubble一樣快。

/* ACM 299
 * mythnc
 * 2011/10/26 09:20:42
 * run time: 0.004
 */
#include <stdio.h>
 
#define MAXARY 50
#define SWAP(x, y, t)  (t = x, x = y, y = t)
 
int bubble1(int *, int, int);
int bubble2(int *, int, int);
 
int main(void)
{
    int n, i, count;
    int ary[MAXARY];
 
    scanf("%*d");
    while (scanf("%d", &n) == 1) {
        if (n == 0) {
            printf("Optimal train swapping takes 0 swaps.\n");
            continue;
        }
        for (i = 0; i < n; i++)
            scanf("%d", &ary[i]);
        for (count = i = 0; i < n - 1; i++)
            if (i % 2 == 0)
                count += bubble1(ary, i / 2, n - (i / 2 + 1));
            else
                count += bubble2(ary, (n - 2) - i / 2, i / 2);
        printf("Optimal train swapping takes %d swaps.\n", count);
    }
    return 0;
}
 
/* bubble1: sort ary from 0 to n */
int bubble1(int *ary, int i, int n)
{
    int c, tmp;
 
    for (c = 0; i < n; i++)
        if (ary[i] > ary[i + 1]) {
            SWAP(ary[i], ary[i + 1], tmp);
            c++;
        }
    return c;
}
 
/* bubble2: sort ary from 0 to n */
int bubble2(int *ary, int i, int n)
{
    int c, tmp;
 
    for (c = 0; i > n; i--)
        if (ary[i] < ary[i - 1]) {
            SWAP(ary[i], ary[i - 1], tmp);
            c++;
        }
    return c;
}

20111025

USACO Greedy Gift Givers

給錢的人要減去錢,分不完的不用分,(-$ + $ % n)
拿到錢的要平分($ / n)。
其實NP是N個人,
也表示有N筆資料要處理,
害我以為輸入資料是不定數了,
(英文太爛,哭哭)
用for代替EOF處理即可。

/*
ID: mythnc2
LANG: C
TASK: gift1
2011/10/25 18:37:46   
*/
#include <stdio.h>
#include <string.h>

#define LEN   20
#define N     10
/* giver: the money giver have to pay */
#define GIVER(person, money, n)  person.money += money % n - money
/* taker: the money taker get */
#define TAKER(person, money, n)  person.money += money / n

typedef struct group {
    char name[LEN + 1];
    int money;
} People;

int findname(People *, char *);
void eatname(FILE *, int);
void printout(FILE *, People *, int);

int main(void)
{
    FILE *fin, *fout;
    int n, i, j, money, ntake;
    char tmp[LEN + 1];
    People person[N];

    fin = fopen("gift1.in", "r");
    fout = fopen("gift1.out", "w");

    fscanf(fin, "%d", &n);
    for (i = 0; i < n; i++) {
        fscanf(fin, "%s", person[i].name);
        person[i].money = 0;    /* init */
    }

    while (1) {
        if (fscanf(fin, "%s", tmp) == EOF) 
            break;
        fscanf(fin, "%d %d", &money, &ntake);
        if (money == 0) {                      /* haven't to give money */
            if (ntake > 0)
                eatname(fin, ntake);
            continue;
        }

        i = findname(person, tmp);             /* the giver name */
        GIVER(person[i], money, ntake);
        for (i = 0; i < ntake; i++) {
            fscanf(fin, "%s", tmp);
            j = findname(person, tmp);         /* the taker name */
            TAKER(person[j], money, ntake);
        }
    }
    /* output */
    printout(fout, person, n);
    return 0;
}

/* findname: find the tmp name in person,
 * return the index of that name */
int findname(People *person, char *tmp)
{
    int i;

    for (i = 0; ; i++)
        if (strcmp(person[i].name, tmp) == 0)
            return i;
}

/* eatname: eat name token */
void eatname(FILE *fin, int n)
{
    while (n--)
        fscanf(fin, "%*s");
}

/* printout: print out the results */
void printout(FILE *fout, People *person, int n)
{
    int i;

    for (i = 0; i < n; i++)
        fprintf(fout, "%s %d\n", person[i].name, person[i].money);
}

USACO Your Ride Is Here

熟悉USACO格式用題目。
每乘一次就做一次mod會比較好。

/*
ID: mythnc2
LANG: C
TASK: ride
*/
#include <stdio.h>
 
#define MAXARY 10
 
int product(char *);
 
int main(void)
{
    FILE *fin, *fout;
    char comet[MAXARY], group[MAXARY];
 
    fin = fopen("ride.in", "r");
    fout = fopen("ride.out", "w");
 
    fscanf(fin, "%s\n", comet);
    fscanf(fin, "%s\n", group);
 
    if (product(comet) == product(group))
        fprintf(fout, "GO\n");
    else
        fprintf(fout, "STAY\n");
    return 0;
}
 
/* product: return the product mod 47 of letters */
int product(char *ary)
{
    int p;
 
    p = 1;
    while (*ary) {
        p *= (*ary - 'A' + 1);
        p %= 47;
        ary++;
    }
    return p;
}

ACM 10300 Ecological Premium

密度 = 面積/動物,
單筆獎金 = 環境友善 * 密度,
總額獎金 = 動物 * 單筆獎金 = 環境友善 * 面積。

/* ACM 10300
 * mythnc
 * 2011/10/25 15:33:42   
 * run time: 0.004
 */
#include <stdio.h>
 
int main(void)
{
    int n, sum, s, e;
 
    scanf("%*d");
    while (scanf("%d", &n) != EOF) {
        for (sum = 0; n; n--) {
            scanf("%d %*d %d", &s, &e);
            sum += s * e;
        }
        printf("%d\n", sum);
    }
    return 0;
}

ACM 136 Ugly Numbers

一開始很天真的以為只要可以被2, 3, 5整除就ok!
實際上是因數只能有2, 3, 5。
最蠢的作法就是從1開始,一直往上找,
能被2, 3, 5整除就記錄下來,如此可以找到第1500筆。
但這實在太慢了!
真的這樣做,會超過3秒TE。
所以就先算出答案,
再直接輸出答案即可。

上傳答案用
#include <stdio.h>
 
int main(void)
{
    puts("The 1500'th ugly number is 859963392.");
    return 0;
}


超級慢會TE的code
/* ACM 136
 * mythnc
 * 2011/10/25 08:44:33   
 * run time: TE
 */
#include <stdio.h>
 
#define NTH 1500
 
int main(void)
{
    int count, n, i;
 
    count = 0;
    n = 0;
    while (count < NTH) {
        n++;
        i = n;
        while (1) {
            if (i == 1) {
                count++;
                break;
            }
            if (i % 2 == 0)
                i /= 2;
            else if (i % 3 == 0)
                i /= 3;
            else if (i % 5 == 0)
                i /= 5;
            else
                break;
        }
    }
    printf("The %d'th ugly number is %d.\n", NTH, n);
    return 0;
}

ACM 494 Kindergarten Counting Game

算word數。
直接做。

/* ACM 494
 * mythnc
 * 2011/10/25 08:35:53   
 * run time: 0.004
 */
#include <stdio.h>
#include <stdlib.h>
 
#define IN  1
#define OUT 0
 
int main(void)
{
    int c, s, count;
 
    s = OUT;
    count = 0;
    while ((c = getchar()) != EOF)
        if (c == '\n') {
            printf("%d\n", count);
            s = OUT;
            count = 0;
        }
        else if (isalpha(c) && s == OUT) {
            count++;
            s = IN;
        }
        else if (!isalpha(c))
            s = OUT;
    return 0;
}

ACM 458 The Decoder

'1' - '*' = 7,
暗碼 - 7即為明碼。

/* ACM 458
 * mythnc
 * 2011/10/25 08:18:04   
 * run time: 0.02
 */
#include <stdio.h>
 
int main(void)
{
    int c;
 
    while ((c = getchar()) != EOF)
        if (c == '\n')
            putchar(c);
        else
            putchar(c - 7);
    return 0;
}

20111024

ACM 913 Joana and the Odd Numbers

1, 3, 5, 7, ... , n,
加總可求出該行最後一個數的值:
1 + 3 + 5 + ... + n,
=> (1 + n) * [(n + 1) / 2] / 2,
=> [(1 + n) / 2] ^ 2。(1)
此值即為等差數列第N項,求N值:
1 + 2 * (N - 1)。 (2)
N用(1)代入
題目求第k - 2, k - 1, k項相加的值,
此值為3 * k - 2 - 4,
k用(2)代入。

直接寫化簡後結果:
(3 / 2) * (n + 1) ^ 2 - 9,
即為答案。

2^63 - 1要用long long type。
除法最後運算,要不然會被吃掉。

/* ACM 913
 * mythnc
 * 2011/10/24 21:38:34   
 * run time: 0.008
 */
#include <stdio.h>

int main(void)
{
    long long n;

    while (scanf("%lld", &n) != EOF) {
        n++;
        printf("%lld\n", 3 * n * n / 2 - 9);
    }
    return 0;
}

ACM 612 DNA Sorting

做sort,但不要sort,
算次數。
'A'可以無視。

/* ACM 612
 * mythnc
 * 2011/10/24 19:32:54   
 * run time: 0.092
 */
#include <stdio.h>

#define LEN  50
#define MAX 100

int dna(char *pt);
int sum_unsorted(char *pt);
void sort_dna(char (*pt)[LEN + 1], int *record, int n);

int main(void)
{
    int set, len, n, i, line;
    char ary[MAX][LEN + 1];
    int record[MAX];

    line = 0;
    scanf("%d", &set);
    while (set--) {
        if (line == 1)
            printf("\n");
        scanf("%d %d", &len ,&n);
        for (i = 0; i < n; i++)
            scanf("%s", ary[i]);
        for (i = 0; i < n; i++)
            record[i] = dna(ary[i]);
        sort_dna(ary, record, n);
        line = 1;
    }
    return 0;
}

/* dna: find the sorted degree of each dna
 * return degrees */
int dna(char *pt)
{
    int sum;

    sum = 0;
    while (*pt)
        switch (*pt) {
            case 'C':
            case 'G':
            case 'T':
                sum += sum_unsorted(pt);
            case 'A':
                pt++;
        }
    return sum;
}

/* sum: sum the unsorted number of each dna 
 * and return it */
int sum_unsorted(char *pt)
{
    int sum;
    char *pt_m;

    sum = 0;
    pt_m = pt;
    while (*++pt_m)
        if (*pt_m < *pt)    
            sum++;
    return sum;
}

/* sort_dna: find the tiniest record to largest 
 * then print the mapping pt sequentially */
void sort_dna(char (*pt)[LEN + 1], int *record, int n)
{
    int min, i;

    while (1) {
        for (min = i = 0; i < n; i++)
            if (record[i] < record[min])
                min = i;
        if (record[min] == 2000)
            break;
        printf("%s\n", pt[min]);
        record[min] = 2000;
    }
}

20111023

ACM 591 Box of Bricks

求平均數,加總比平均數大的值。

/* ACM 591
 * mythnc
 * 2011/10/23 11:22:21   
 * run time: 0.004
 */
#include <stdio.h>

#define MAX 50

int main(void)
{
    int n, set, i, avg, move;
    int ary[MAX];

    set = 0;
    while(scanf("%d", &n) != EOF){
        if(n == 0)
            return 0;
        set++;
        for(avg = i = 0; i < n; i++){
            scanf("%d", ary + i);
            avg += ary[i];
        }
        avg /= n;
        for(move = i = 0; i < n; i++)
            if(ary[i] > avg)
                move += ary[i] - avg;
        printf("Set #%d\nThe minimum number of moves is %d.\n\n",
                set, move);
    }
}


ACM 579 ClockHands

時針1hr走30(360/12)度,
所以時針1min走30/60度,
分針1min走360/60度。
所以角度公式為:
30H + (1/2)H - 6M。

/* ACM 579
 * mythnc
 * 2011/10/23 10:52:58   
 * run time: 0.032
 */
#include <stdio.h>
 
int main(void)
{
    int h, m;
    double angle;
 
    while (scanf("%d:%d", &h, &m) == 2) {
        if (h == 0 && m == 0)
            return 0;
        angle = 30 * h + 0.5 * m - 6 * m;
        if (angle < 0)
            angle = -angle;
        if (angle > 180)
            angle = 360 - angle;
        printf("%.3f\n", angle);
    }
}

20111022

ACM 541 Error Correction

每row與column都要是偶數,
才符合property。
若存在唯一奇數,
使row跟column因為這個數被改變就能變偶數,
就改變他。
超過一個奇數就不用處理。

好像就直接做嘛……我也不知道我在寫啥。
第一次用(*)[]的寫法來接收二維陣列,效果不錯。

/* ACM 541
 * mythnc
 * 2011/10/22 20:33:45   
 * run time: 0.008
 */
#include <stdio.h>

#define MAX 99
#define ONE  1
#define MORE 0

void property(int (*)[MAX], int);
int oddnumber(int *, int *, int);

int main(void)
{
    int n, i, j;
    int ary[MAX][MAX];
    
    while (scanf("%d", &n) == 1) {
        if (n == 0)
            return 0;
        for (i = 0; i < n; i++)
            for (j = 0; j < n; j++)
                scanf("%d", &ary[i][j]);

        property(ary, n);
    }
}

/* property: find the matrix has partity property or not */
void property(int (*pt)[MAX], int n)
{
    /* sum[0]: sum of each row, sum[1]: sum of each column */
    /* record[0]: bit row, sum[1]: bit column */
    int i, j, sum[2], record[2];

    for (record[0] = record[1] = i = 0 ; i < n; i++) {
        for (sum[0] = sum[1] = j = 0; j < n; j++) {
            sum[0] += pt[i][j]; /* sum of each row */
            sum[1] += pt[j][i]; /* sum of each column */
        }
        /* judge row and column*/
        for (j = 0; j < 2; j++)
            if (oddnumber(&sum[j], &record[j], i) == MORE) {
                printf("Corrupt\n");
                return;
            }
    }
    if (record[0] == 0 && record[1] == 0)
        printf("OK\n");
    else
        printf("Change bit (%d,%d)\n", record[0], record[1]);
}

/* oddnumber: calculate the odd number,
 * record it's row and column
 * if no odd or only 1 odd return ONE
 * if more then 1 odd return MORE
 */
int oddnumber(int *sum, int *record, int i)
{
    if (*sum % 2 == 1 && *record == 0)
        *record = i + 1;
    else if (*sum % 2 == 1 && *record > 0)
        return MORE;
    return ONE;
}

ACM 477 Points in Figures: Rectangles and Circles

ACM476進階版。
多了圓。
算點到圓心的距離即可。

/* ACM 477
 * mythnc
 * 2011/10/22 12:19:02   
 * run time: 0.012
 */
#include <stdio.h>

#define IN  1
#define OUT 0
#define CIR 1
#define REC 0
#define MAX 10
/* DISTANCE: calculate the range of (x, y) and center of cir */
#define DISTANCE(x, y, x1, y1) (x - x1) * (x - x1) + (y - y1) * (y - y1)
/* SQUARE: calculate x^2 */
#define SQUARE(x) x * x

int main(void)
{
    double pic[MAX][4], x, y;
    /* f: number of pic, k: number of (x, y) */
    int f, k, n, i, c;
    int record[MAX] = { REC };

    /* receive r */
    f = 0;
    while ((c = getchar()) != '*')
        if (c == 'r') {
            scanf("%lf %lf %lf %lf", &pic[f][0], &pic[f][1], &pic[f][2], &pic[f][3]);
            f++;
        }
        else if (c == 'c') {
            scanf("%lf %lf %lf", &pic[f][0], &pic[f][1], &pic[f][2]);
            record[f++] = CIR;
        }

    k = 1;
    while (scanf("%lf %lf", &x, &y) == 2) {
        if (x == 9999.9 && y == 9999.9)
            return 0;
        for (n = OUT, i = 0; i < f; i++)
            if (record[i] == REC) {
                if (x > pic[i][0] && x < pic[i][2] && y > pic[i][3] && y < pic[i][1]) {
                    printf("Point %d is contained in figure %d\n", k, i + 1);
                    n = IN;
                }
            }
            else if (record[i] == CIR)
                if (DISTANCE(x, y, pic[i][0], pic[i][1]) < SQUARE(pic[i][2])) {
                    printf("Point %d is contained in figure %d\n", k, i + 1);
                    n = IN;
                }
        if (n == OUT)
            printf("Point %d is not contained in any figure\n", k);
        k++;
    }
    return 0;
}

20111021

ACM 476 Points in Figures: Rectangles

很懶另外用function處理,
直接做。
矩形的座標(x1, y1)跟(x2, y2),
與(x, y)做比較,若在其中就是在矩形內。

/* ACM 476
 * mythnc
 * 2011/10/21 16:13:45   
 * run time: 0.02
 */
#include <stdio.h>

#define IN  1
#define OUT 0

int main(void)
{
    double r[10][4], x, y;
    /* kr: number of r, k: number of (x, y) */
    int kr, k;
    int n, i;
    char c;

    kr = 0;
    /* receive r */
    while ((c = getchar()) != '*')
        if (c == 'r') {
            scanf("%lf %lf %lf %lf", &r[kr][0], &r[kr][1], &r[kr][2], &r[kr][3]);
            kr++;
        }

    k = 1;
    while (scanf("%lf %lf", &x, &y) == 2) {
        if (x == 9999.9 && y == 9999.9)
            break;
        for (n = OUT, i = 0; i < kr; i++)
            if (x > r[i][0] && x < r[i][2] && y > r[i][3] && y < r[i][1]) {
                printf("Point %d is contained in figure %d\n", k, i + 1);
                n = IN;
            }
        if (n == OUT)
            printf("Point %d is not contained in any figure\n", k);
        k++;
    }
    return 0;
}

ACM 468 Key to Success

一開始以為FREQUENCY的值一定是一樣的,真是好天真啊!
FREQUENCY只是relative而已。
所以這題的作法是:找出第一行FREQUENCY、找出第二行FREQUENCY,
對FREQUENCY做sort、兩行的FREQUENCY做map,最後才解碼。

另外這題沒說明測資大小,所以array如果預設太小,是會無限WA的,
真是怎麼死的都不知道啊 XD。
array就給他10000設下去吧。
(看討論區有人說某題的測資還要設100000,才會過 -_-)
/* ACM 468
 * mythnc
 * 2011/10/21 14:43:51   
 * run time: 0.048
 */
#include <stdio.h>
#include <ctype.h>

#define ALPHABET 52
#define LINEMAX  10000

typedef struct letters {
/* c: save letter name,
 * count: counts the letter time */
    char c;
    int count;
} Text;

int line(char *, Text *, int);
int save(Text *, char, int);
void sort(Text *, int);
void swap(Text *, int, int);
void output(char *, Text *, Text *, int);
char findkey(char, Text *, Text *, int);

int main(void)
{
    int n, i, index;
    Text key[ALPHABET], encode[ALPHABET];
    char tmp[LINEMAX];

    scanf("%d", &n);
    getchar();  /* eat '\n' after n */
    for (i = 0; i < n; i++) {
        getchar();  /* eat blank line */
        /* handle line1 */
        fgets(tmp, LINEMAX, stdin);
        index = 0;
        index = line(tmp, key, index);
        sort(key, index);
        /* handle line2 */
        fgets(tmp, LINEMAX, stdin);
        index = 0;
        index = line(tmp , encode, index);
        sort(encode, index);
        /* handle output */
        if (i > 0)
            printf("\n");
        output(tmp, key, encode, index);
    }
    return 0;
}

/* line: find letter in line, return index of target */
int line(char *pt, Text *target, int index)
{
    for (; *pt != '\n'; pt++)
        if (isalpha(*pt))
            index = save(target, *pt, index);
    return index;
}

/* save: find c in t or not, if not, add c in t
 * return count of Text t */
int save(Text *t, char c, int count)
{
    int i;

    for (i = 0; i < count; i++)
        if (t[i].c == c) {   /* if find, return directly */
            t[i].count++;
            return count;
        }
    /* if not find, add it */
    t[count].c = c;
    t[count++].count = 1;
    return count;
}

/* sort: sort pt from high to low */
void sort(Text *pt, int count)
{
    int i, j, max;

    /* selection sort */
    for(i = 0; i < count - 1; i++) {
        max = i;
        for (j = i; j < count; j++)
            if (pt[j].count > pt[max].count)
                max = j;
        if (max != i)
            swap(pt, max, i);
    }
}

/* swap: swap the contents of x and y */
void swap(Text *pt, int x, int y)
{
    Text tmp;

    tmp = pt[x];
    pt[x] = pt[y];
    pt[y] = tmp;
}

/* output: output encode text */
void output(char *pt, Text *key, Text *encode, int count)
{
    for (; *pt != '\0'; pt++)
        if (isalpha(*pt))
            printf("%c", findkey(*pt, key, encode, count));
        else
            printf("%c", *pt);
}

/* findkey: find correspond key and return it */
char findkey(char c, Text *key, Text *encode, int count)
{
    int i;

    for (i = 0; i < count; i++)
        if (encode[i].c == c)
            return key[i].c;
}

20111020

ACM 445 Marvelous Mazes

直接做。 用數字表示ascii code會比較快, 但不好理解。

/* ACM 445
 * mythcn
 * 2011/10/20 16:47:21
 * run time: 0.024
 */
#include <stdio.h>
 
int main(void)
{
    int c, num;
 
    num = 0;
    while ((c = getchar()) != EOF)
        if (c > '0' && c <= '9')
            num += (c - '0');
        else if (c >= 'A' && c <= 'Z' || c == '*')
            while (num > 0) {
                putchar(c);
                num--;
            }
        else if (c == 'b')
            while (num > 0) {
                putchar(' ');
                num--;
            }
        else if (c == '!' || c == '\n')
            putchar('\n');
    return 0;
}

ACM 406 Prime Cuts

先找到1到1000的所有質數,存起來。
再根據input做相對應output。
1記得也要存,雖然他不是質數 -_-

/* ACM 406
 * mythnc
 * 2011/10/20 15:50:21   
 * run time: 0.064
 */
#include <stdio.h>
 
#define MAXARY 200
#define N      1000
#define NOT_P  0
#define PRIME  1
 
int prime(int *);
int maxnumber(int *, int, int);
void output(int *, int, int);
 
int main(void)
{
    int n, c, pnumber, ptotal;
    int ary[MAXARY];
 
    ptotal = prime(ary);
    while (scanf("%d %d", &n, &c) == 2) {
        pnumber = maxnumber(ary, n, ptotal);
        printf("%d %d:", n, c);
        output(ary, pnumber, c);
        printf("\n\n");
    }
    return 0;
}
 
/* prime: find prime from 1 to 1000, save in s
 * return the numbers */
int prime(int *s)
{
    int i, j, count, rec;
 
    count = 0;
    s[count++] = 1;
    s[count++] = 2;
    for (i = 3; i < N + 1; i += 2) {
        rec = PRIME;
        for (j = 3; j * j <= i; j += 2)
            if (i % j == 0) {
                rec = NOT_P;
                break;
            }
        if (rec == PRIME)
            s[count++] = i;
    }
    return count;
}
 
/* maxnumber: return the prime number from 1 to n */
int maxnumber(int *s, int n, int max)
{
    int i;
 
    for (i = 0; s[i] <= n && i < max; i++)
        ;
    return i;
}
 
 
/* output: output result */
void output(int *s, int pnum, int c)
{
    int i, mid;
 
    mid = pnum / 2;
    /* print all */
    if (mid < c)
        for (i = 0; i < pnum; i++)
            printf(" %d", s[i]);
    /* pnum is odd */
    else if (pnum % 2 == 1)
        for (i = mid - c + 1; i < mid + c; i++)
            printf(" %d", s[i]);
    /* pnum is even */
    else
        for (i = mid - c; i < mid + c; i++)
            printf(" %d", s[i]);
}

20111019

ACM 344 Roman Digititis

最簡單的作法就是直接解。
偷吃步的方法就是先算好1-100的所有情況,
再根據input直接output XD。

/* ACM 344
 * mythnc
 * 2011/10/19 11:09:01   
 * run time: 0.02
 */
#include <stdio.h>

#define ARYMAX 5

void sum(int *, int);
void init(int *);

int main(void)
{
    int n;
    /* num element: 0:i, 1:v, 2:x, 3:l, 4:c */
    int num[ARYMAX];

    while (scanf("%d", &n) != EOF) {
        if (n > 0) {
            init(num);
            sum(num, n);
            printf("%d: %d i, %d v, %d x, %d l, %d c\n",
                   n, num[0], num[1], num[2], num[3], num[4]);
        }
        else
            break;
    }
    return 0;
}

/* init: initialize num elements to 0 */
void init(int *num)
{
    int i;

    for (i = 0; i < ARYMAX; i++)
        num[i] = 0;
}

/* sum: summation the digits from 1 to n */
void sum(int *num, int n)
{
    int i;

    for (i = 1; i < n + 1; i++) {
        switch (i % 10) {
            case 1:
                num[0]++;
                break;
            case 2:
                num[0] += 2;
                break;
            case 3:
                num[0] += 3;
                break;
            case 4:
                num[0]++;
                num[1]++;
                break;
            case 5:
                num[1]++;
                break;
            case 6:
                num[1]++;
                num[0]++;
                break;
            case 7:
                num[1]++;
                num[0] += 2;
                break;
            case 8:
                num[1]++;
                num[0] += 3;
                break;
            case 9:
                num[2]++;
                num[0]++;
                break;
            case 0:
            default:
                break;
        }
        switch (i / 10) {
            case 1:
                num[2]++;
                break;
            case 2:
                num[2] += 2;
                break;
            case 3:
                num[2] += 3;
                break;
            case 4:
                num[2]++;
                num[3]++;
                break;
            case 5:
                num[3]++;
                break;
            case 6:
                num[3]++;
                num[2]++;
                break;
            case 7:
                num[3]++;
                num[2] += 2;
                break;
            case 8:
                num[3]++;
                num[2] += 3;
                break;
            case 9:
                num[4]++;
                num[2]++;
                break;
            case 10:
                num[4]++;
                break;
            case 0:
            default:
                break;
        }
    }
}

ACM 272 TEX Quotes

直接做,紀錄"是第幾次出現即可。

/* ACM 272
 * mythnc
 * 2011/10/19 10:26:34   
 * run time: 0.004
 */
#include <stdio.h;>

#define FIRST  1
#define SECOND 2

int main(void)
{
    int c, n;

    n = FIRST;
    while ((c = getchar()) != EOF)
        if (c == '"')
            if(n % 2 == 1) {
                printf("``");
                n = SECOND;
            }
            else {
                printf("''");
                n = FIRST;
            }
        else
            putchar(c);
    return 0;
}

20111018

ACM 264 Count on Cantor

找規則
分子                       分母
1             第1行          1
2 1           第2行        1 2
3 2 1         第3行      1 2 3
4 3 2 1       第4行    1 2 3 4
5 4 3 2 1     第5行  1 2 3 4 5

第3(1+2)個term的分子是2
第6(1+2+3)個term的分母是3
第10(1+2+3+4)個term的分子是4
第15(1+2+3+4+5)個term的分母是5
第21(1+2+3+4+5+6)個term的分子是6
第28(1+2+3+4+5+6+7)個term的分母是7

i從2往上累加,超過term為止。
判斷i是奇數還是偶數,
p = term - 累加值。p表示在該行相對於尾端(i)的位置。
每行的分母+分子 = 行數(i)+1。
所以求出其中之一,另一個即為i + 1 - 分母(或分子)。
奇數行: [(i + 1) - (i - p)] / (i - p),
偶數行: (i - p) / [(i + 1) - (i - p)]。
/* ACM 264
 * mythnc
 * 2011/10/18 14:18:56   
 * run time: 0.008
 */
#include <stdio.h>

void findterm(int);

int main(void)
{
    int n;

    while (scanf("%d", &n) != EOF)
        if (n == 1)
            printf("TERM %d IS 1/1\n", n);
        else
            findterm(n);
    return 0;
}

/* findterm: find term and print it */
void findterm(int n)
{
    int sum, i, p;

    for (i = 2, sum = 1; sum < n; i++)
        sum += i;
    p = sum - n;
    if (--i % 2 == 0)   /* judge i is even line or odd line */
        printf("TERM %d IS %d/%d\n", n, i - p, 1 + p);
    else
        printf("TERM %d IS %d/%d\n", n, p + 1, i - p);
}

ACM 113 Power of Cryptography

做p ^ (1/n)次,就是答案。

/* ACM 113
 * mythnc
 * 2011/10/18 09:17:44   
 * run time: 0.008
 */
#include <stdio.h>
#include <math.h>
 
int main(void)
{
    double p, n;
 
    while (scanf("%lf %lf", &n, &p) != EOF)
        printf("%.0lf\n", pow(p, 1 / n));
    return 0;
}

20111017

ACM 107 The Cat in the Hat

可憐的小貓負責做苦工。
假設第一隻貓的身高為H,
需要作工的的貓數量為W。

一開始,貓的數量1,貓的身高H,
叫貓一次之後,
貓的數量共1 + N,
貓的總身高H + H * N / (1 + N)。
叫貓第二次,
貓的數量共1 + N + N ^ 2,
貓的總身高H + H * N / (1 + N) + H * N^2 / (1 + N) ^ 2。
叫貓第三次,
貓的數量共1 + N + N ^ 2 + N ^ 3,
貓的總身高H + H * N / (1 + N) + H * N^2 / (1 + N) ^ 2 + H * N^3 / (1 + N) ^ 3。
叫貓第k次,
貓的數量共1 + N + N ^ 2 + N ^ 3 + ... + N ^ k,
貓的總身高H + H * N / (1 + N) + H * N^2 / (1 + N) ^ 2 + H * N^3 / (1 + N) ^ 3 + ... + H * N^k / (1 + N) ^ k。

第k次的貓,身高為H / (1 + N) ^ k,數量為N ^ k,
根據題目說明,此貓身高為1,數量為W:
(1)1 = H / (1 + N) ^ k,所以H = (1 + N) ^ k,
(2)W = N ^ k。

由等比級數公式[1 - r^(k+1)] / 1 - r可得。(公比為r)
貓的數量:[1 - N^(k+1)] / (1 - N),
不用作工貓的數量,就是算到k-1次的意思:
{[1 - N^(k-1 + 1)] / (1 - N)}
展開化簡:
(3)(1 - W) / (1 - N)。

全部的貓身高加總
H + H * N / (1 + N) + H * N^2 / (1 + N) ^ 2 + H * N^3 / (1 + N) ^ 3 + ... + H * N^k / (1 + N) ^ k,
H * [1 + N / (1 + N) + N^2 / (1 + N) ^ 2 + N^3 / (1 + N) ^ 3 + ... + N^k / (1 + N) ^ k],
(忽然想學LaTex,要不然這樣打數學公式實在有夠辛苦)
反正[]內的東西是等差級數,我直接寫化簡結果:
(4)H * (N + 1) - W * N。
(用H、W代入就可以化簡)

由(3)(4)可知只要知道N,就能計算偷懶貓與總貓身高了。
那N怎麼求呢?
H = (1 + N) ^ k
W = N ^ k
可以知道存在唯一N使得此N的k次方跟(1+N)的k次方為W、H。
所以N從2開始往上代,只要滿足
N跟N + 1對W、H取餘數為0,
滿足的話,就計算W /= N、H /= N + 1,再取餘數,再/=,
反覆到W == 1跟N == 1為止。
若取餘數不為0,或不滿足W == 1跟N == 1,
N++往上代。

話說這裡想好久,囧,同時算H、W,
比先算其中一個再算另一個還快。

另外公式的部份要注意N = 1會讓分母為0(害我一直RE),
所以N = 1的情況要特別處理。(即W = 1的情況)

2011/11/08 update:
幫人檢查code,發現到
原來H跟W差1的情況下,
N就是W。
例如:30 29
N為29
答案就是1 59(30 + 29)。
Code可以改寫囉! 
/* ACM 107
 * mythnc
 * 2011/10/17 19:16:52   
 * run time: 0.064
 */
#include <stdio.h>

int findn(int, int);

int main(void)
{
    int w, h, n;

    while (scanf("%d %d", &h, &w) == 2) {
        if (!h && !w)
            break;
        if (h == 1) {
            printf("0 1\n");
            continue;
        }
        if (w == 1) {
            while ((h >> w) != 1)
                w++;
            printf("%d %d\n", w, 2 * h - 1);
            continue;
        }
        n = findn(h, w);
        printf("%d %d\n", (w - 1) / (n - 1), (n + 1) * h - w * n);
    }
    return 0;
}

/* findn: find and return the constant N */
int findn(int h, int w)
{
    int n, i, j;

    n = 2;
    while (1) {
        i = w;
        j = h;
        /* n have to divide w and j */
        while (i % n == 0 && j % (n + 1) == 0) {
            i /= n;
            j /= n + 1;
            if (i == 1 && j == 1)
                return n;
        }
        n++;
    }
}

ACM 10491 Cows and Cars

三門問題。
題目的敘述異常的清楚……
是說每個討論三門問題的人都跟題目一樣清楚就好了。

由題目可以得知:
牛門cow個,車門car個,打開牛門show個。
如果一開始選的是牛門,主持人打開n個牛門,換門後選到車門的機率是:
一開始選牛門的機率 * 剩下的門中選到車門的機率。
即,(牛門/總門) * [車門/(總門-開門數-1)]。 (1)
如果一開始選的是車門,主持人打開n個牛門,換門後選到車門的機率是:
一開始選車門的機率 * 剩下的門中選到車門的機率。
即,(車門/總門) * [(車門-1)/(總門-開門數-1)]。 (2)

(1) + (2)即為換門後選到車門的機率。

/* ACM 10491
 * mythnc
 * 2011/10/17 11:08:44   
 * run time: 0.012
 */
#include <stdio.h>

int main(void)
{
    int cow, car, show;
    int total, left;

    while (scanf("%d %d %d", &cow, &car, &show) != EOF) {
        total = cow + car;
        left = total - show - 1;
        printf("%.5f\n", (double)cow / total * car / left +
                         (double)car / total * (car - 1) / left);
    }
    return 0;
}

ACM 10370 Above Average

直接做。
求average,算大於average的個數,
輸出%比。

/* ACM 10370
 * mythnc
 * 2011/10/17 10:04:00   
 * run time: 0.008
 */
#include <stdio.h>
 
#define MAXARY 1000
 
int main(void)
{
    int n, c, i, count;
    int ary[MAXARY];
    double avg;
 
    scanf("%d", &c);
    while (c--) {
        scanf("%d", &n);
        for (avg = i = 0; i < n; i++) {
            scanf("%d", ary + i);
            avg += ary[i];
        }
        avg /= n; 
        for (count = i = 0; i < n; i++)
            if (ary[i] > avg)
                count++;
        printf("%.3f%%\n", (double)count / n * 100);
    }
    return 0;
}

ACM 10327 Flip Sort

bubble sort、cocktail sort、merge sort都符合。
速度上 merge > cocktail > bubble。
merge sort第一次寫,想好久……
主要是要另外給一個儲存空間才比較好實作。
直接宣告array大小比用malloc動態分配快耶 -_-。

/* ACM 10327
 * mythnc
 * 2011/10/17 08:52:53   
 * run time: 0.016
 * merge sort
 */
#include <stdio.h>
 
#define MAXARY 1000
 
int divide(int *, int *, int, int);
 
int main(void)
{
    int n, i;
    int ary[MAXARY], tmp[MAXARY];
 
    while (scanf("%d", &n) != EOF) {
        for (i = 0; i < n; i++)
            scanf("%d", ary + i);
        printf("Minimum exchange operations : %d\n",
               divide(ary, tmp, 0, n));
    }
    return 0;
}

/* divide: merge sort ary */
int divide(int *ary, int *tmp, int head, int tail)
{
    int half, i, j, k, c;
 
    /* already sorted */
    if (tail - head == 1)
        return 0;
    /* unsorted list -> divide into 2 sub lists */
    c = 0;
    half = (head + tail - 1) >> 1;
    c += divide(ary, tmp, head, half + 1);
    c += divide(ary, tmp, half + 1, tail);
    /* sort 2 sublists and merge */
    k = i = head;
    j = half+1;
    while (i < half + 1 && j < tail)
        if (ary[j] < ary[i]) {
            tmp[k++] = ary[j++];
            c += half + 1 - i;
        }
        else
            tmp[k++] = ary[i++];
    while (i < half + 1)
        tmp[k++] = ary[i++];
    while (j < tail)
        tmp[k++] = ary[j++];
    for (i = head; i < tail; i++)  /* copy the sorted list to ary*/
        ary[i] = tmp[i];
    return c;
}

20111015

ACM 10257 Dick and Jane

n歲的定義:過了n歲的生日,但還沒過n+1歲的生日,這個期間,都是n歲。

由題目可知
(1)Spot s歲時,Puff出生。
(2)Puff p歲時,Yertle出生。
(3)Spot y歲時,Yertle出生。
(4)Dick + Jane = Spot + Puff + Yertle
由(1)(2)(3)可知大小順序: Spot > Puff > Yertle。

以年紀最小的Y往上推:
(a)當Y x歲時,P為 x+p歲或 x+p + 1歲。
(b)當Y x歲時,S為 x+y歲或 x+y + 1歲。

由(a)(b)可得總歲數sum的所有可能情況:
x + (x+p) + (x+y)
x + (x+p) + (x+y+1)
x + (x+p+1) + (x+y)
x + (x+p+1) + (x+y+1)

由sum求x:
sum = 12(d歲) + j歲 = 3x + p + y + (0or1or2)
x = [(12+j) - p - y - (0or1or2)] / 3
以下分別解釋每種情況。

第一種:x = [(12+j) - p - y - 0] / 3
歡樂解,直接輸出S、P、Y的年齡:x+y、x+p、x

第二種:x = [(12+j) - p - y - 1] / 3
(12+j) - p - y要減1之後才能被3整除,
所以用3對(12+j) - p - y取餘數,一定餘1。
餘1的情況有兩種:S+1或P+1。
由(a)(1)可以推導出
(c)當P x+p歲時  ,S為(x+p)   + s歲或(x+p)   + s + 1歲。
(d)當P x+p+1歲時,S為(x+p+1) + s歲或(x+p+1) + s + 1歲。

(d)是P+1的情況,所以(c)一定是S+1,把兩式化簡再跟(b)做比較:

(c)當P x+p歲時  ,S為(x+p) + s + 1 = x+y+1
(d)當P x+p+1歲時,S為(x+p+1) + s   = x+y
刪x
(c)當P x+p歲時  ,S為p + s + 1 = x+y+1
(d)當P x+p+1歲時,S為p+1 + s   = x+y 
最後可得
(c)p + s = y
(d)p + s + 1 = y
所以判斷p + s是否等於y,就能知道是S+1或P+1。

第三種:x = [(12+j) - p - y - 2] / 3
減2才能被3整除,所以用3對(12+j) - p - y - 2取餘數
會餘2。即S、P要各+1再輸出。

打字好多好累 -_-|
簡單講,就是Y x歲生日時,S跟P可能生日過了(各+1),
或是其中一個過了(S+1 or P+1),或是都還沒過。
/**
/* ACM 10257
 * mythnc
 * 2011/10/15 20:11:27   
 * run time: 0.004
 */
#include <stdio.h>

int main(void)
{
    int s, p, y, j, x; /* x: Yertle's age */

    while (scanf("%d %d %d %d", &s, &p, &y, &j) == 4) {
        x = (12 + j - p - y) / 3;
        switch((12 + j - p - y) % 3) {
            case 0:
                printf("%d %d %d\n", x + y, x + p, x);
                break;
            case 1:
                if (s + p == y)
                    printf("%d %d %d\n", x + y + 1, x + p, x);
                else
                    printf("%d %d %d\n", x + y, x + p + 1, x);
                break;
            case 2:
                printf("%d %d %d\n", x + y + 1, x + p + 1, x);
                break;
        }
    }
    return 0;
}

ACM 10235 Simply Emirp

如何判斷n是不是質數?
最簡單的方法就是2到n-1去除n,
若能被整除,那就不是質數。
但在實作上不會這麼笨,只要從2到√n就可以了。
因為如果n是合數,n就可以拆成2個數字,
而其中一個數字,會<=√n。

/* ACM 10235
 * mythnc
 * 2011/10/15 13:29:01   
 * run time: 0.012
 */
#include <stdio.h>

#define PRIME 1
#define NOT_P 0

int prime(int);
int reverse(int);

int main(void)
{
    int n;

    while (scanf("%d", &n) != EOF) {
        if (prime(n))
            if (reverse(n))
                printf("%d is emirp.\n", n);
            else
                printf("%d is prime.\n", n);
        else
                printf("%d is not prime.\n", n);
    }
    return 0;
}

/* prime: judge n is prime or not */
int prime(int n)
{
    int i;

    if (n == 2)           /* 2 is prime */
        return PRIME;
    if (n % 2 == 0)       /* even is not prime */
        return NOT_P;
    for (i = 3; i * i <= n; i++)
        if (n % i == 0)
            return NOT_P;
    return PRIME;
}

/* reverse: return prime(the reverse n) */
int reverse(int n)
{
    int x, tmp;

    tmp = n;
    x = n % 10;
    while ((n /= 10) > 0) {
        x *= 10;
        x += n % 10;
    }
    if (x == tmp)    /* if reverse n is the same n */
        return 0;    /* can't output emirp */
    return prime(x);
}

ACM 10209 Is This Integration ?

畫輔助線後答案就出來了。





















x表示斜線面積、y點狀面積(4塊)、z剩下的(4塊)
由畢式定理:紅色三角形邊長比為1:√3:2
即是,算出紅色三角形面積 + 30度的扇形面積,
與半個正方形面積的差值,為半個z:
(a^2)/2 - [(1/2) * (a/2) * (√3a/2) + (30/360) * πa^2]
乘2後可得z:
a^2 - (√3a^2)/4 - (πa^2)/6

利用z來求y值,
y為正方形面積與90度扇形面積+2個z的差值:
a^2 - [(90/360) * πa^2 + 2z]
化簡後可得y:
a^2 - (πa^2)/4 - 2z
最後中間那塊x即為正方形面積與4塊(y+z)面積的差值:
a^2 - 4z - 4y

請無視我寫的E跟F(掩面),看來我少標一個點……

/* ACM 10209
 * mythnc
 * 2011/10/15 00:01:27   
 * run time: 0.040
 */
#include <stdio.h>
#include <math.h>

int main(void)
{
    /* x: striped region, y: dotted region, z: the rest */
    /* y and z have 4 pieces */
    /* output x directly: a^2 - 4y - 4z */
    double a, y, z;
    double const pi = 3.1415926535897931159980;

    while (scanf("%lf", &a) != EOF) {
        a *= a; /* a mean a^2 now */
        z = 4*a - 2*pi*a / 3 - a*sqrt(3); /* z mean 4z now */
        y = 4*a - pi*a - 2*z; /* y mean 4y now */
        printf("%.3f %.3f %.3f\n", a - y - z, y, z);
    }
    return 0;
}

20111014

ACM 102 Ecological Bin Packing

移動的瓶子 + 沒移動的瓶子 = 總瓶數
換句話說,沒移動的瓶子越多,移動的瓶子就會越少。
排列組合共有6種情況:3 * 2 * 1。
分別計算每一種情況下,沒移動的瓶子數。
找到最大數之後,與總瓶數相減,即為最少移動瓶子數。
想說不要直接算移動瓶子數應該會比較快,有嗎?
我也不知道……
code可讀性應該很差……

保險一點用unsigned int才不會overload,
但既然AC就懶得改了。 -_-

/* ACM 102
 * mythnc
 * 2011/10/14 19:22:33   
 * run time: 0.028
 */
#include <stdio.h>

#define MAXARY 6  /* six permutations */
#define BIN    3

int findmax(int *);
void output(int *);

int main(void)
{
    int b, c, g, i;
    /* cmp counts bottles which don't have to move */
    /* each element to a permutation */
    int cmp[MAXARY]; 

    i = 0;
    while (scanf("%d %d %d", &b, &g, &c) == 3) {
        switch (i++) {
            case 0:
                cmp[0] = cmp[1] = b;
                cmp[2] = cmp[3] = c;
                cmp[4] = cmp[5] = g;
                break;
            case 1:
                cmp[0] += c;
                cmp[1] += g;
                cmp[2] += b;
                cmp[3] += g;
                cmp[4] += b;
                cmp[5] += c;
                break;
            case 2:
                cmp[0] += g;
                cmp[1] += c;
                cmp[2] += g;
                cmp[3] += b;
                cmp[4] += c;
                cmp[5] += b;
                /* sum of element 0, 3, 4 is the total bottles */
                output(cmp);
                i = 0;
        }
    }
    return 0;
}

/* findmax: find the max element of s */
int findmax(int *s)
{
    int i, max;

    for (max = i = 0; i < MAXARY; i++)
        if (s[i] > s[max])
            max = i;
    return max;
}

/* output: output result */
void output(int *s)
{
    switch(findmax(s)) {
        case 0:
            printf("BCG %d\n", s[3]+s[4]);
            break;
        case 1:
            printf("BGC %d\n", s[2]+s[5]);
            break;
        case 2:
            printf("CBG %d\n", s[1]+s[5]);
            break;
        case 3:
            printf("CGB %d\n", s[0]+s[4]);
            break;
        case 4:
            printf("GBC %d\n", s[0]+s[3]);
            break;
        case 5:
            printf("GCB %d\n", s[1]+s[2]);
    }
}

20111013

ACM 101 The Blocks Problem

除了硬幹好像也沒別招了?
不過儲存資料的結構實在長的很噁心……
之前用2維陣列存,這次試著用結構存看看
本題可以練習到stack的運作方式。
之前ACM10038 free就被WA,
這次free就沒事 -_-。

/* ACM 101
 * mythnc
 * 2011/10/14 16:08:24   
 * run time: 0.008
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAXARY 25

typedef struct robot {
    int *block;
    int count;
} Action;

void init(Action *[], int n);
int position(Action *[], int *, int);
void clear(Action *[], int *);
void move(Action *[], int *, int *);
void print(Action *[], int);

int main(void)
{
    /* a[3]: 0 for a, 1 for position a, 2 for block a */
    /* same as b */
    int n, a[3], b[3];
    char str1[MAXARY], str2[MAXARY];
    Action *arm[MAXARY];

    scanf("%d", &n);
    init(arm, n);
    while (scanf("%s %d %s %d", str1, a, str2, b) == 4) {
        if (a[0] == b[0])
            continue;
        if ((a[1]= position(arm, a, n)) ==
            (b[1]= position(arm, b, n)))
            continue;
        if (strcmp(str1, "move") == 0)
            clear(arm, a);
        if (strcmp(str2, "onto") == 0)
            clear(arm, b);
        move(arm, b, a);
    }
    print(arm, n);
    return 0;
}

/* init: initialize arm */
void init(Action *arm[], int n)
{
    int i;

    for (i = 0; i < n; i++) { /* initialize arm */
        arm[i] = (Action *)malloc(sizeof(Action));
        arm[i]->block = (int *)malloc(sizeof(int) * n);
        arm[i]->count = 0;
        arm[i]->block[arm[i]->count++] = i;
    }
}

/* position: return position and block of pt[0] */
int position(Action *arm[], int *pt, int n)
{
    int i, j;

    for (i = 0; i < n; i++)
        for (j = 0; j < arm[i]->count; j++)
            if (arm[i]->block[j] == pt[0]) {  /* position i, block j */
                pt[2] = j;
                return i;
            }
}

/* clear: clear blocks above x */
void clear(Action *arm[], int *x)
{
    int tmp;

    while (arm[x[1]]->count != x[2] + 1) {  /* return tmp to it's position */
        tmp = arm[x[1]]->block[--arm[x[1]]->count];
        arm[tmp]->block[arm[tmp]->count++] = tmp;
    }
}

/* move: move a to b */
void move(Action *arm[], int *b, int *a)
{
    int i;

    for (i = a[2]; i < arm[a[1]]->count; i++)
        arm[b[1]]->block[arm[b[1]]->count++] = arm[a[1]]->block[i];
    arm[a[1]]->count = a[2];
}

/* print: print out final state */
void print(Action *arm[], int n)
{
    int i, j;

    for (i = 0; i < n; i++) {
        printf("%d:", i);
        for (j = 0; j < arm[i]->count; j++)
            printf(" %d", arm[i]->block[j]);
        free(arm[i]->block);
        free(arm[i]);
        printf("\n");
    }
}

ACM 10071 Back to High School Physics

直接做。

/* ACM 10071
 * mythnc
 * 2011/10/13 18:58:58   
 * run time: 0.02
 */
#include <stdio.h>

int main(int argc, char *argv[])
{
    int t, v;

    while (scanf("%d %d", &v, &t) != EOF )
        printf("%d\n", 2 * v * t);
    return 0;
}

ACM 10062 Tell me the frequencies!

概念同ACM10008
也是沒想到比較好的算則。
ary0到95對應ascii code 32到127。
由小至大輸出,ascii code高的優先。

/* ACM 10062
 * mythnc
 * 2011/10/13 18:48:47
 * run time: 0.004
 */
#include <stdio.h>

int output(int *);

int main(void)
{
    int c, newline;
    int ary[96] = { 0 };

    newline = 0;
    while ((c = getchar()) != EOF) {
        if (c > 31 && c < 128)
            ary[c - 32]++;
        if (c == '\n') {
            if (++newline > 1)
                printf("\n");
            while (output(ary))
                ;
        }
    }
    return 0;
}

/* output: print out the result from high ascii value to low */
int output(int *s)
{
    int i, j, min;

    for (min = 1001, i = 95; i > -1; i--)
        if (min > s[i] && s[i] > 0) {
            min = s[i];
            j = i;
        }
    if (min == 1001)   /* if no element have to printed */
        return 0;
    printf("%d %d\n", j + 32, min);
    s[j] = 0;
    return 1;
}

ACM 10056 What is the Probability ?

機率好難……
一開始的想法很單純,答案就是題目給的浮點數。
後來想想發現,第i個人擲骰,i未必為1,
而也未必在第一輪就骰出。
所以我想的太簡單了 -.-。
所以正確的思考方式應該為:
n個人中第k個人骰贏得機率是多少?
此人可能在第一輪骰贏、第二輪骰贏、第三輪骰贏……一直到他骰贏的那輪為止。
假設骰贏的機率為p,沒骰贏的機率為q = p - 1
第k個人要骰贏,前面k-1個人一定不會骰贏:
q ^ (k-1)
此人自己需骰贏:
q ^ (k-1) * p
如果他沒骰贏,遊戲被迫進入第二輪,
即第一輪大家都沒骰贏:
q ^ n
第二輪中他骰贏的情況(第一輪沒人贏,第二輪他贏):
(q ^ n) * q ^ (k-1) * p
第三輪中他骰贏的情況(前二輪沒人贏,第三輪他贏):
(q ^ 2n) * q ^ (k-1) * p
類推,到第x+1輪他骰贏的情況(前x輪沒人贏,第x+1輪他贏):
(q ^ xn) * q ^ (k-1) * p
所以若要計算他所有骰贏的可能情況,
就是第一輪骰贏的機率 + 第二輪骰贏的機率 + ... + 第x輪骰贏的機率:
q ^ (k-1) * p + (q ^ n) * q ^ (k-1) * p + (q ^ 2n) * q ^ (k-1) * p + ... + (q ^ xn) * q ^ (k-1) * p
以下化簡原式:
  1. q ^ (k-1) * p [1 + (q ^ n) + (q ^ 2n) + ... + (q ^ xn)] (取出q ^ (k-1)*p)
  2. 1 + (q ^ n) + (q ^ 2n) + ... + (q ^ xn) 是無窮等比級數(根本就不知道他哪一輪會贏)
公比為q ^ n。
所以2.式可以化簡為1 / (1 - q ^ n)(查詢等比級數公式/無窮等比級數公式)
原式化簡為:
[q ^ (k-1) * p] / (1 - q ^ n)。
另外要注意,當p為0時,此公式分母為0,所以輸出需另外處理。
(就是輸出0.0000而已啦)

/* ACM 10056
 * mythnc
 * 2011/10/13 11:47:52   
 * run time: 0.008
 */
#include <stdio.h>
#include <math.h>

int main(void)
{
    int set, n, k;  /* n players, the kth player */
    double p;

    scanf("%d", &set);
    while (set-- > 0) {
        scanf("%d %lf %d", &n, &p, &k);
        if (p == 0.0) {
            printf("0.0000\n");
            continue;
        }
        if (k == 1)
            printf("%.4f\n", p / (1 - pow(1-p, n)));
        else
            printf("%.4f\n", p * pow(1-p, k-1) / (1 - pow(1-p, n)));
    }
    return 0;
}

ACM 10055 Hashmat the Brave Warrior

直接做。
2 ^ 32比unsigned int多1,所以用long long int存資料囉。
要不然會WA。

/* ACM 10055
 * mythnc
 * 2011/10/13 09:47:17   
 * run time = 0.06
 */
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    long long int x, y;

    while (scanf("%lld %lld",&x,&y) != EOF)
        if (x > y)
            printf("%lld\n", x - y);
        else
            printf("%lld\n", y - x);
    return 0;
}

ACM 10038 Jolly Jumpers

當n > 1,
用malloc分配n-1個空間,
0到n-2分別對應1到n-1。
對應要1對1剛剛好,不可少,不可多, 才符合jolly jumper。
這題一直RE,
最後不用free()就AC了,
偉哉ACM,不給free()。
真正在寫code,有malloc()就要有free()。
2011/10/13 update:
有一個地方free()會RE,
但其他地方可free(),真怪 orz。

/* ACM 10038 Jolly Jumpers
 * mythnc
 * 2012/03/31 21:03:04
 * run time: 0.008
 */
#include <stdio.h>
#include <stdlib.h>

typedef enum {FALSE = 0, TRUE} bool;

bool jolly(int);

int main(void)
{
    int n;

    while (scanf("%d", &n) != EOF) {
        if (n == 1) {
            scanf("%*d");
            printf("Jolly\n");
            continue;
        }
        if (jolly(--n))
            printf("Jolly\n");
        else
            printf("Not jolly\n");
    }
    return 0;
}

/* jolly: judge the sequence is jolly or not */
bool jolly(int interval)
{
    int i, x, next;
    bool *seq;

    seq = (bool *)malloc(sizeof(bool) * interval);
    for (i = 0; i < interval; i++)         /* initialize seq */
        seq[i] = FALSE;
    scanf("%d", &x);
    for (i = 0; i < interval; i++) {
        scanf("%d", &next);
        x = abs(x - next);
        /* x have to appear only once or not be a jolly jumper*/
        if (x > 0 && x <= interval && seq[x-1] == FALSE) {
            seq[x-1] = TRUE;
            x = next;
        }
        else {  /* eat remain input string */
            while (getchar() != '\n')
                ;
            /* free(seq); can not free or runtime error */
            return FALSE;
        }
    }
    for (i = 0; i < interval; i++)
        if (seq[i] == FALSE) {
            free(seq);
            return FALSE;
        }
    free(seq);
    return TRUE;
}

20111012

ACM 10035 Primary Arithmetic

取x跟y的個位數,相加,若進位,則carry數+1。
之後x與y各除以10,反覆之,到兩數除以10皆為0止。
需考慮99999 1的carry數。
carry數會影響下一個carry數的判斷,需注意。

/* ACM 10035
 * mythnc
 * 2u11/10/12 20:48:47   
 * run time = 0.02
 */
#include <stdio.h>

int carry(int, int);

int main(void)
{
    int x, y, n;

    while (scanf("%d %d", &x, &y) == 2) {
        if (x == 0 && y == 0)
            break;
        if ((n = carry(x, y)) == 1)
            printf("1 carry operation.\n");
        else if (n == 0)
            printf("No carry operation.\n");
        else
            printf("%d carry operations.\n", n);
    }
    return 0;
}

/* carry: calculate the carry times */
int carry(int x, int y)
{
    int n, c;

    c = n = 0;
    while (x != 0 || y != 0) {   /* same as !(x==0 && y==0) */
        if (x % 10 + y % 10 + c > 9) {
            n++;
            c = 1;
        }
        else
            c = 0;
        x /= 10;
        y /= 10;
    }
    return n;
}

ACM 10018 Reverse and Add

4,294,967,295為unsigned int的上限。
主要是reverse函數會寫,答案就出來了。
unsigned int好長一串,就用typedef了 -_-。

/* ACM 10018
 * mythnc
 * 2011/10/12 19:38:26
 * run time = 0.008
 */
#include <stdio.h>

#define MAXARY 15

typedef unsigned int number;

number reverse(number);

int main(void)
{
    int n, count;
    number x, y;

    scanf("%d", &n);
    while (n-- > 0) {
        scanf("%u", &x);
        count = 0;
        while (x != (y = reverse(x))) {
            x += y;
            count++;
        }
        printf("%d %u\n", count, x);
    }
    return 0;
}

/* reverse: reverse the digits of x */
number reverse(number x)
{
    number y;

    y = 0;
    do {
        y *= 10;
        y += x % 10;
        x /= 10;
    } while (x != 0);
    return y;
}

ACM 10008 What's Cryptanalysis?

還沒想到好的方法……
利用一個array[26]從0到25分別對應A(a)到Z(z),
初始為0。
每次從stdin接收一個字母後,對應該字母的element + 1。
輸出時,從array[0]到array[25]找最大的element,
輸出之,輸出後把該element歸0。反覆,到所有elements為0為止。

/* ACM 10008
 * mythnc
 * 2011/10/13 09:10:55   
 * run time = 0.004
 */
#include <stdio.h>
#include <ctype.h>

int printout(int *s);

int main(void)
{
    int c;
    int alpha[26] = {0};

    scanf("%*d");
    while ((c = getchar()) != EOF)
        if (isupper(c))
            alpha[c - 'A']++;
        else if (islower(c))
            alpha[c - 'a']++;
    while (printout(alpha))
        ;
    return 0;
}

/* printout: print array s from high to low sequence */
int printout(int *s)
{
    int i, j, max;

    max = 0;
    for (i = 0; i < 26; i++)
        if (max < s[i]) {
            max = s[i];
            j = i;
        }
    if (max == 0)       /* if no letter have to be outputed */
        return 0;
    printf("%c %d\n", 'A' + j, max);
    s[j] = 0;
    return 1;
}

ACM 100 The 3n + 1 problem

直接做。 要小心i可能小於j的情況。

/* ACM 100 The 3n + 1 problem
 * mythnc
 * 2011/11/30 09:10:17
 * version 1.2
 * run time: 0.592
 */
#include <stdio.h>

int count(int);
int cal(int, int);

int main(void)
{
    int i, j;

    while (scanf("%d %d", &i, &j) == 2)
        printf("%d %d %d\n", i, j, j > i ? cal(i, j) : cal(j, i));

    return 0;
}

/* cal: find the big cycle len, and return it */
int cal(int small, int big)
{
    int i, max, tmp;

    for (max = 0, i = small; i <= big; i++) {
        tmp = count(i);
        if (max < tmp)
            max = tmp;
    }

    return max;
}

/* count: count the numbers of value n to 1 */
int count(int n)
{
    int c;

    for (c = 1; n != 1; c++)
        if(n % 2 == 0)
            n >>= 1;    /* n /= 2 */
        else 
            n = n * 3 + 1;

    return c;
}

ACM前言

ACM一個有很多題目,讓Programmer練習寫成是的網站。
評論有好有壞。
我還記得以前修計概的老師特別喜歡ACM,
他覺得好處多多,寫個200-300題上台清交研究所不是問題。
也有人覺得ACM只不過是在玩input/output的處理。

總而言之,程式寫出來總是好的。
另外我都用C寫code。

20111011

The C Programming Language

More about The C Programming Language
終於還是把這本書看完了。
說是C語言的聖經書,當之無愧。
從著名的hello world開始,
到system call。
也是我看過的書中,
唯一把array跟pointer一起講的。
言簡意賅,每句話都是重點,都是關鍵。
金字塔般的編書方式與程式範例,
讓你像疊疊樂一樣,一層一層往上疊。

每個練習題都要動動腦,不會有白痴問題。
(不過題目有些寫好短,看不是很懂)

同樣都是寫書,都是在教程式語言,
外國人就是寫得比較好,真納悶……
難怪一堆人寧願看原文書也不看中文書了。