USACO Section 1.1

1 Your Ride Is Here

将给出的名字(长度1-6)中的A-Z映射为1-26,判断给出的两个名字对应的字母乘积模47是否相同,是输出“GO”,否则输出“STAY”。

#include <stdio.h>

int main (int argc, char* argv[]) {
    FILE *fin  = fopen ("ride.in", "r");
    FILE *fout = fopen ("ride.out", "w");

    int comet, group, i;
    char cn[8], gn[8], *ptr;

    fscanf (fin, "%s", cn);
    fscanf (fin, "%s", gn);

    for (comet = 1, ptr = cn; *ptr; ++ptr)
        comet *= *ptr -'A'+1;
    for (group = 1, ptr = gn; *ptr; ++ptr)
        group *= *ptr -'A'+1;
    fprintf (fout, "%s\n", (comet%47 == group%47) ? "GO" : "STAY");
    
    exit (0);
}

 

2 Greedy Gift Givers

给出每个人的名字以及对应的礼品金额、朋友数和朋友的名字,算出每个人最后的盈亏。(NP问题?2<= NP <=10)

下面解法复杂度为O(n^3),利用哈希表可以降为O(n^2)

#include <stdio.h>
#include <stdlib.h>

long hash(char *s){
    long code = *s-'a';
    while (*++s) code = code*10 + *s-'a';
    return code;
}

typedef struct{
    char name[20];
    long hashcode;
    int amount;
} Person;

int main (int argc, char *argv[]) {
    FILE *fin  = fopen ("gift1.in", "r");
    FILE *fout = fopen ("gift1.out", "w");
    int n, i, average, amount, friends;
    char name[20];
    long hashcode;
    Person *people, *who, *whom;

    fscanf(fin, "%d", &n);

    people = (Person*)malloc(sizeof(Person)*n);
    for (i = 0; i < n; ++i){
        fscanf(fin, "%s", people[i].name);
        people[i].hashcode = hash(people[i].name);
        people[i].amount = 0;
    }

    for (i = 0; i < n; ++i){
        fscanf(fin, "%s", name);
        fscanf(fin, "%d %d", &amount, &friends);
        for (hashcode = hash(name), who = people;
             who->hashcode != hashcode;
             ++who);
           
        if (amount && friends){
            average = amount/friends;
            who->amount -= average*friends;
           while (friends--){
               fscanf(fin, "%s", name);
               for (hashcode = hash(name), whom = people;
                whom->hashcode != hashcode;
                ++whom);
               whom->amount += average;
           }}
    }

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

    exit (0);
}

3 Friday the Thirteenth

已知1900年1月1日是星期一,给出N(1 <= N <= 400),算出1900年1月1日至1900+N-1年12月31日中13号落在周一到周日的次数。

#include <stdio.h>

int leap_year(int year){
    return (year%100==0) ? year%400==0 : year%4==0;
}

int months[] = {31, 28, 31, 30,
                31, 30, 31, 31,
                30, 31, 30, 31};

int counts[7];

int main (int argc, char *argv[]) {
    FILE *fin  = fopen ("friday.in", "r");
    FILE *fout = fopen ("friday.out", "w");
 
     int n, i, j, at=6;
     fscanf(fin, "%d", &n);
     for (i = 0; i < n; ++i){
         for (j = 0; j < 12; ++j){
             counts[at]++;
             at = (at + months[j] + (j==1 && leap_year(1900+i)))%7;
         }
     }

     fprintf(fout, "%d %d %d %d %d %d %d\n",
             counts[6], counts[0], counts[1], counts[2], counts[3], counts[4], counts[5]); 
    exit (0);
}

4 Broken Necklace

给出项链的串(如brbrrrbbbrrrrrbrrbbrbbbbrrrrb,对应图A),求出从某个地方断开能收集的珠子的最大长度。

规则:分别向左和向右开始收集同颜色的珠子直到你遇到一个不同的颜色珠子(白色当作红色或绿色)。

                1 2                               1 2
            r b b r                           b r r b
          r         b                       b         b
         r           r                     b           r
        r             r                   w             r
       b               r                 w               w
      b                 b               r                 r
      b                 b               b                 b
      b                 b               r                 b
       r               r                 b               r
        b             r                   r             r
         b           r                     r           r
           r       r                         r       b
             r b r                             r r w
            Figure A                         Figure B
                        r red bead
                        b blue bead
                        w white bead

简单的搜索也能AC,复杂度O(n^2),我想了个比较笨的方法,理论上的是O(n)

/*
ID: shaojie2
LANG: C
TASK: beads
*/
#include <stdio.h>

/*
 * 因为只需考虑断点在红与蓝之间的情况,所以
 * 先将输入处理为一个个{颜色,长度}的节点,
 * 并假设输入的串里红与蓝中间一定会有白色节点(长度可以为零),就像:
 * ... [w x1] [r x2] [w x3] [b x4] [w x5] [r x6] ...
 *       w0    pre     w1     cur    w2    next
 * 从 x1 到 x5 的五个节点的总长度即是从 x3 分开的长度。
 * 每次处理完 next 节点就开始处理前面的五个节点。
 * 将原输入两倍化以便消除头尾连接问题。
 */

struct {
    int color; /* Zero is reguarded as WHITE */
    int len;
} white1, pre, white2, cur, white3, next;

char beads[701];
int max_len = 0;

int main (int argc, char *argv[]) {
    FILE *fin  = fopen ("beads.in", "r");
    FILE *fout = fopen ("beads.out", "w");
    int N, i = 0, total = 0;

    fscanf (fin, "%d", &N);
    fscanf (fin, "%s", beads);
    for (i = 0; i < N; ++i) beads[N+i] = beads[i];
    beads[N*=2] = '\0';

    i = 0;
    while(i < N){
WHITE_2:
        white2.len = 0;
        while (i < N && beads[i] == 'w')
            ++ white2.len, ++i;
        if (i == N) break;
CUR:
        cur.color = beads[i];
        cur.len = 0;
        while (i < N && beads[i] == cur.color)
            ++ cur.len, ++i;
        if (cur.color == pre.color){ //颜色相同则合并节点
            pre.len += cur.len + white2.len;
            goto WHITE_2;
        }       
        if (i == N) break;

WHITE_3:
        white3.len = 0;
        while (i < N && beads[i] == 'w')
            ++ white3.len, ++i;
        if (i == N) break;
NEXT:
        next.color = beads[i];
        next.len = 0;
        while (i < N && beads[i] == next.color)
            ++ next.len, ++i;
        if (next.color == cur.color){ //颜色相同则合并节点
            cur.len += next.len + white3.len;
            goto WHITE_3;
        }
        if (i == N)break;

        //计算在 pre 和 cur 之间断开能收集的长度
        total = white1.len + pre.len + white2.len + cur.len + white3.len;
        if (total > max_len) max_len = total;
        else
            total -= white3.len;
        //移动节点
        white1 = white2;
        pre = cur;
        white2 = white3;
        cur = next;
        goto WHITE_3;
    }
    total = white1.len + pre.len + white2.len + cur.len + white3.len;
    if (total > max_len) max_len = total;

    //若最大长度比给定的长度还长,则说明正条项链都可以被收集
    fprintf (fout, "%d\n",
             max_len > N/2 ? N/2 : max_len); 
    exit (0);
}

 

 

 

 

 

 

 

 

转载于:https://www.cnblogs.com/lu-x/archive/2013/02/07/2908255.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值