分类: 技术

  • 奖学金 解题报告

    这是个水题,我直接使用了库函数qsort进行了排序,然后输出前五个就可以了,唯一想要说的就是明天或后天把Glibc中的qsort代码看下,学习一下是怎么对超级巨大的数据量进行快速排序的,一个个交换肯定不是,这些都明天再说吧。

    #include <stdio.h>
    #include <stdlib.h>
    #define MAX 300
    struct grade{
     int a, b, c;
     int id;
    }totle[MAX];
    int compare(const void *a, const void *b)
    {
     struct grade i = *(struct grade *)a, j = *(struct grade *)b;
     int sum1 = i.a + i.b + i.c,
     sum2 = j.a + j.b + j.c;
     if(sum1 == sum2){
     if(i.a == j.a){
     return i.id - j.id;
     }
     return j.a - i.a;
     }
     return sum2 - sum1;
    }
    
    int main(void)
    {
     int i;
     int n;
     scanf(%d, &n);
     for(i = 0; i < n; i++){
     totle[i].id = i + 1;
     scanf(%d%d%d, &totle[i].a, &totle[i].b, &totle[i].c);
     }
     qsort(totle, n, sizeof(struct grade), compare);
     for(i = 0; i < 5; i++){
     printf(%d %d\\n, totle[i].id, totle[i].a + totle[i].b +
     totle[i].c);
     }
     return 0;
    }
  • 2^k进制数 解题报告

    这题困扰了我好几天,详细看了别人的题解,自己反复琢磨,终于琢磨透了。
    把我的思路讲一下,f[i][j] 表示第i位(从右向左数, 如12中的1是第二位),则很容易得到一个DP:
    f[i][j] = f[i – 1][j + 1] + f[i – 1][j + 2] + f[i – 1][j + 3] + …. + f[i – 1][n] (n为极限,放在后面讲。)
    不用说,用这个递推公式绝对会超时,所以还需要对公式观察一下:
    f[i][j] = f[i – 1][j + 1] + f[i – 1][j + 2] + f[i – 1][j + 3] + …. + f[i – 1][n]
    上面用红色标记出来的能够用f[i][j + 1] 表示,怎么来的?呵呵,就是因为
    f[i][j] = f[i – 1][j + 1] + f[i – 1][j + 2] + f[i – 1][j + 3] + …. + f[i – 1][n] 所以
    f[i][j + 1] = f[i – 1][j + 2] + f[i – 1][j + 3] + …. + f[i – 1][n].所以
    f[i][j] = f[i][j + 1] + f[i – 1][j + 1]
    这就好求了,但是这里需要从大数向小数递减(即j是从n – 1 递减到 1)
    然后,我提供一个小剪枝,第i个数的最大值位(1 << k) – j,比如只有一位数字的时候(题目要求至少两位,但是这里只是说明。)当k=3的时候,第一位能够选择的数字是1-7;当有两位数字且k=3是,第二位就只能是1~6而不是1~7了(自己思考下)

    还有一个重要的就是需要高精度!!别人都说int要压4位运算,但是这里我压了9位,原因很简单,压4位数的原因是99999^2 > 2^32,就是说当遇到最坏情况下的乘法时,只能使用4位,5位就会溢出;但是这个题目要清楚一点,高精度只用实现加法!所以可以压9位,再多的话也是会超时的。
    代码就在下面提供了吧:

    
    #include <stdio.h>
    #define MAX 24
    #define USED 1000000000
    #define max(a, b) ((a)>(b)?(a):(b))
    typedef unsigned bignum[MAX];
    bignum count[513][513];
    bignum ans;
    
    void add(bignum a, bignum b)
    {
     int i, j, t;
     int c = max(a[0], b[0]);
     unsigned to = 0;
     if(a[0] < b[0]){
     a[0] = b[0];
     }
     for(i = 0; i < c; i++){
     t = MAX - 1 - i;
     a[t] += b[t] + to;
     to = a[t] / USED;
     if(to > 0){
     a[t] %= USED;
     }
     }
     if(to != 0){
     a[MAX - 1 - i] = to; //狂晕,,, 这里的to写成了t 
     a[0]++;
     }
    }
    
    void output(bignum n)
    {
     int i, t;
     for(i = MAX - n[0]; i <= MAX - 1; i++){
     printf(%.*d, (i == MAX - n[0]) ? 0 : 9, n[i]);
     }
    }
    
    int main(void)
    {
     int i, j;
     int top, limit;
     int k, w, n;
     scanf(%d%d, &k, &w);
     n = w / k;
     top = limit = (1 << k) - 1;
     if(w - n * k > 0){
     top = (1 << (w - n * k)) - 1;
     n++;
     }
     if(limit < n){
     n = limit;
     }
     for(i = 1; i <= limit; i++){
     count[1][i][0] = 1;
     count[1][i][MAX - 1] = 1;
     }
     for(i = 2; i <= n; i++){
     for(j = limit - i + 1; j >= 1; j--){
     add(count[i][j], count[i - 1][j + 1]);
     add(count[i][j], count[i][j + 1]);
     }
     }
     for(i = 2; i < n; i++){
     for(j = 1; j <= limit; j++){
     add(ans, count[i][j]);
     }
     }
     for(j = 1; j <= top; j++){
     add(ans, count[i][j]);
     }
     output(ans);
     return 0;
    }
  • Glibc 的 strcmp

    Glibc的设计确实巧妙的让人想不到,如下strcmp的代码就十分巧妙:

    C语言: Codee#12462

    int
    strcmp (p1, p2)
     const char p1;
     const char p2;
    {
     register const unsigned char s1 = (const unsigned char ) p1;
     register const unsigned char s2 = (const unsigned char ) p2;
     unsigned reg_char c1, c2;
    
     do
     {
     c1 = (unsigned char) s1++;
     c2 = (unsigned char) s2++;
     if (c1 == \'\\0\')
     return c1 - c2;
     }
     while (c1 == c2);
    
     return c1 - c2;
    }

    它使用了寄存器变量就会很快了,又只是用了两个判断来确定循环是否继续,这才是程序的关键!因为如果c2==\’\0\’的话,那么c1有两种情况,第一c1不等于\’\0\’,这种情况下那就会不满足c1 == c2 这个条件,退出循环;然而如果c1也等于\’\0\’的话,那么程序满足c1 == \’\0\’的条件,那退出程序。

  • 快速成法

      当x乘以n的时候,一般人使用的是mul指令(即直接相乘),而我会使用位运算来优化这些速度,比如乘以3,就等于((x << 1) + x),相当于2x+x 就是3x了,然而这后者的速度比前者的速度快很多。
      乘以3只是一个情况,乘以n的话,就要把n拆分成2的次方相加,更一般地,就是把n用二进制表示,然后把位为1的进行处理,没表达清楚吧,再举个例子:5,它的二进制是101,也就是4+1,那么就可以把n5表示成4n+n,也就是((n << 2) + n),再比如8把,8*n的二进制是1000,也就是2^3,那么就可以写成(n << 3)
      现在发现位运算比很多运算要快很多!!

  • 快速置零 xor %eax, %eax

      在<<Linux 内核完全注释>>里面看到了几次xor ax, ax,很想不通,为什么不直接用mov ax, 0呢?今日到网上一搜才知道,我的天啊,xor ax, ax 只需要计算机2条指令,而mov ax, 0会消耗计算机5指令,什么意思?就是近三倍的速度差别。

  • [转]as86的man

    as86(1)                                                                as86(1)

    名称
          as86 – as86-8086..80386
    处理器的汇编程序

    概要格式
          as86  [-0123agjuw]  [-lm[list]]  [-n name]  [-o obj] [-b[bin]] [-s sym]
          [-t textseg] src

          as86_encap prog.s prog.v [prefix_] [as86 options]

    描述
         as86
    是8086..80386处理器下的汇编程序,它所采用的语法与Intel/MS采取的语法类似,而不同于广泛运用于UNIX下的汇编语法(译注,gas中的语法,AT&T汇编)

        命令行中的src参数可为‘-‘,代表对标准输入进行汇编。

        as86_encap是一个脚本,使用了as86汇编程序,并且把生成的二进制文件转为一个C文件prog.v,用于被连接或者包含到程序里,例如引导块安装程序。prefix_参数定义一个加到源文件中所有定义的变量的前缀,缺省前缀是源文件名。…

    选项
         -0    
    以16位代码段运行,当使用了高于8086指令集的指令时警告。

         -1     以16位代码段运行,当使用了高于80186指令集的指令时警告。

         -2     以16位代码段运行,当使用了高于80286指令集的指令时警告。

         -3     以32位代码段运行,不对任何指令发出警告信息(就算使用了486或586的指令)

         -a     使汇编程序部分兼容于Minix asld.交换了[]与()的用法,并且改变了一些16位跳转与调用的语法(“jmp @(bx)” 就成了一个合法的指令)

         -g     仅仅把global符号写入目标或者符号文件中

         -j     把所有短跳转指令(译注:8位跳转称为短跳转)换成相似的16位或者32位跳转。并且把16位条件转移指令换为一个条件短转移命令与一个无条件长跳转组合

         -O     汇编程序会做几遍额外的工作,以尝试支持向前引用。最多30遍。不推荐使用

         -l     产生清单文件(list file),文件名写在选项后

         -m     把宏展开后写在清单文件里

         -n     把模块名写在选项之后(目标模块,而非源文件)

         -o     生成目标文件,文件名写在选项之后

         -b     生成纯二进制文件,文件名写在后面。这是一个没有头部的纯二进制文件(译注:类似Dos下的com和sys)如果没有-s选项程序将会在内存地址0处开始执行

         -s     生成一个ASCII码符号文件,文件名写在选项后。很简单就能将其转换,用于与-b选项生成的二进制文件相关联和封装。如果二进制文件不从地址0处开始执行。那么符号文件表中前两项分别代表起始地址与结束地址

         -u     假定未定义符号在未指定的段中被导入了

         -w-    允许汇编程序输出警告信息

         -t n   把所有text段的数据放到段n+3中.

    AS86 资料
         
    特殊字符

         *    本行起始地址

         ;或! 注释起始符,另外,在一行起始处的“unexpected”字符被认为是注释(但是仍然会被显示在终端上)

         $      16进制数的前缀, C风格的前缀, 比如0x1234, 也可以使用.

         %      2进制数的前缀.

         #      立即数的前缀.

         [ ]    间接寻址运算符.

                与MASM不同,汇编程序没有标识符的类型信息,每个标识符仅仅代表是一个段地址和偏移地址。[]与立即数操作与传统汇编程序一致

                 例:

                      mov     ax,bx

                      jmp     bx

                 寄存器寻址, jmp指令把bx寄存器中的值拷到程序计数器中

                      mov ax,[bx]

                      jmp [bx]

                 简单的寄存器间接寻址, jmp指令把bx寄存器值指向的内存单元的值拷到程序计数器中

                      mov ax,#1234

                 立即数, 把1234赋值给ax寄存器

                      mov ax,1234

                      mov ax,_hello

                      mov ax,[_hello]

                 直接寻址,内存地址1234处的存储字赋给ax寄存器。注意第三个指令并不十分严格,只是为了与asld保持兼容所以保留(译注:若想将_hello标识符表示的值作为立即数使用,需要加上#前缀 #_hello)

                      mov ax,_table[bx]

                      mov ax,_table[bx+si]

                      mov eax,_table[ebx*4]

     

                      mov ax,[bx+_table]

                      mov ax,[bx+si+_table]

                      mov eax,[ebx*4+_table]

                 变址寻址。两种形式都可以,但是我认为第一种要更正确些,但是我往往用第二种形式🙂

          条件判断

          IF, ELSE, ELSEIF, ENDIF

                 数字比较

          IFC, ELSEIFC

                 字符串比较 (str1,str2)

     

         FAIL .FAIL

                 生成用户错误

          段相关

          .TEXT .ROM .DATA .BSS
                 
    设置当前段。可以在前面加上关键字.SECT

          LOC    数字表示段 0=TEXT, 3=DATA,ROM,BSS, 14=MAX.  连接器设定的段顺序现在是0,4,5,6,7,8,9,A,B,C,D,E,1,2,3.段 0 以及所有3以上的段都假设为text段。注意64K限制对3-14的段不适用。

         标识符类型定义

          EXPORT PUBLIC .DEFINE
                 
    导出符号

          ENTRY  强制连接器在a.out文件里包含这个特殊符号

          .GLOBL .GLOBAL
                 
    将一个标识符定义为外部的,并且强制就算不使用,也必须导入

          EXTRN EXTERN IMPORT .EXTERN
                 
    导入外部标识符列表

    NB: bin格式的文件不支持外部变量(译注:关于这些格式,推荐参考一下NASM的手册。纯C论坛上有中文的NASM手册)

          .ENTER 标识出旧式bin格式(obs)的程序入口

          数据定义

          DB .DATA1 .BYTE FCB
                 1
    字节的对象列表

          DW .DATA2 .SHORT FDB .WORD
                 2
    字节的对象列表

          DD .DATA4 .LONG
                 4
    字节的对象列表

          .ASCII FCC
               
    写到输出的Ascii码字符串.

          .ASCIZ Ascii 写到输出的Ascii码字符串,末尾添加nul

          空间定义

          .BLKB RMB .SPACE
                 
    以字节为单位计算空间

          .BLKW .ZEROW
                 
    以字为单位计算空间 (一字2字节)

          COMM .COMM LCOMM .LCOMM
                 
    通用数据域定义

          其他实用伪指令

          .ALIGN .EVEN
                 
    对齐

          EQU    定义标识符(译注:可参考NASM或者MASM的EQU)

          SET    定义可重定义的标识符

          ORG .ORG
                 
    定义汇编位置(译注:即设置地址计数器的值,建议参考MASM的资料)

          BLOCK  定义汇编位置并且把原来的汇编位置入栈

          ENDB   回到刚才栈里记录的汇编位置

          GET INCLUDE
                 
    插入新文件 (no quotes on name)

    USE16 [cpu]
           
    定义默认操作数大小为16位,参数表示程序代码将会运行在什么样的CPU的(86,186, 286,386,486,586)指令集上.使用了指定指令集之上的指令会产生警告信息

    USE32 [cpu]
           
    定义默认操作数大小为32位,参数表示程序代码将会运行在什么样的CPU的(86,186,     286,386,486,586)指令集上.使用了指定指令集之上的指令会产生警告信息

          END    标识出本文件停止汇编的地方

          .WARN  警告信息开关

          .LIST  清单 on/off (1,-1)

          .MACLIST
                 
    宏清单 on/off (1,-1)

         宏的使用形式如下

              MACRO sax
                 mov ax,#?1
              MEND
              sax(1)

         未实现/未使用的

          IDENT  Define object identity string.

          SETDP  Set DP value on 6809

          MAP    Set binary symbol table map number.

         寄存器
                 BP BX DI SI
                 EAX EBP EBX ECX EDI EDX ESI ESP
                 AX CX DX SP
                 AH AL BH BL CH CL DH DL
                 CS DS ES FS GS SS
                 CR0 CR2 CR3 DR0 DR1 DR2 DR3 DR6 DR7
                 TR3 TR4 TR5 TR6 TR7 ST

         操作数类型说明
                 BYTE DWORD FWORD FAR PTR PWORD QWORD TBYTE WORD NEAR

                 near和far关键字并没有提供段间寻址编程的能力,所有”far”操作都是
                 
    都是通过显式地使用以下指令得到的:指令: jmpi, jmpf, callf, retf,
                
    等等. Near关键字可以被用来强制使用80386的16位条件跳转指令
    .
                 ‘Dword’
    和‘word’ 能控制远跳转和远调用的操作数的大小

         普通指令.
                 
    这些指令和其他8086汇编程序所提供的指令大体上差不多,(译注:后面的
                
    看不明白了.我的英语功底啊~555) the main exceptions being a few ‘
                 Bcc’ (BCC, BNE,  BGE,  etc)  instructions which are shorthands f
                 or a short branch plus a long jump and ‘BR’ which is the longest
                 unconditional jump (16 or 32 bit).

          长分支
                 BCC  BCS  BEQ  BGE BGT BHI BHIS BLE BLO BLOS BLT BMI BNE BPC BPL
                 BPS BVC BVS BR

          段间操作
                 CALLI CALLF JMPI JMPF

         段修饰符指令
                 ESEG FSEG GSEG SSEG

         字节操作指令
                 ADCB ADDB ANDB CMPB DECB DIVB IDIVB IMULB  INB  INCB  MOVB  MULB
                 NEGB  NOTB ORB OUTB RCLB RCRB ROLB RORB SALB SARB SHLB SHRB SBBB
                 SUBB TESTB XCHGB XORB

         标准指令
                 AAA AAD AAM AAS ADC ADD AND ARPL BOUND BSF BSR BSWAP BT BTC  BTR
                 BTS CALL CBW CDQ CLC CLD CLI CLTS CMC CMP CMPS CMPSB CMPSD CMPSW
                 CMPW CMPXCHG CSEG CWD CWDE DAA DAS DEC DIV DSEG ENTER  HLT  IDIV
                 IMUL  IN  INC  INS  INSB INSD INSW INT INTO INVD INVLPG INW IRET
                 IRETD J JA JAE JB JBE JC JCXE JCXZ JE JECXE JECXZ JG JGE JL  JLE
                 JMP  JNA JNAE JNB JNBE JNC JNE JNG JNGE JNL JNLE JNO JNP JNS JNZ
                 JO JP JPE JPO JS JZ LAHF LAR LDS LEA LEAVE LES LFS LGDT LGS LIDT
                 LLDT  LMSW  LOCK  LODB  LODS  LODSB  LODSD LODSW LODW LOOP LOOPE
                 LOOPNE LOOPNZ LOOPZ LSL LSS LTR MOV MOVS MOVSB MOVSD MOVSW MOVSX
                 MOVW  MOVZX  MUL  NEG NOP NOT OR OUT OUTS OUTSB OUTSD OUTSW OUTW
                 POP POPA POPAD POPF POPFD PUSH PUSHA PUSHAD PUSHF PUSHFD RCL RCR
                 REP REPE REPNE REPNZ REPZ RET RETF RETI ROL ROR SAHF SAL SAR SBB
                 SCAB SCAS SCASB SCASD SCASW SCAW SEG SETA SETAE SETB SETBE  SETC
                 SETE SETG SETGE SETL SETLE SETNA SETNAE SETNB SETNBE SETNC SETNE
                 SETNG SETNGE SETNL SETNLE SETNO  SETNP  SETNS  SETNZ  SETO  SETP
                 SETPE  SETPO SETS SETZ SGDT SHL SHLD SHR SHRD SIDT SLDT SMSW STC
                 STD STI STOB STOS STOSB STOSD STOSW STOW STR SUB TEST VERR  VERW
                 WAIT WBINVD XADD XCHG XLAT XLATB XOR

          浮点
                 F2XM1  FABS  FADD  FADDP FBLD FBSTP FCHS FCLEX FCOM FCOMP FCOMPP
                 FCOS FDECSTP FDISI FDIV FDIVP  FDIVR  FDIVRP  FENI  FFREE  FIADD
                 FICOM  FICOMP  FIDIV  FIDIVR FILD FIMUL FINCSTP FINIT FIST FISTP
                 FISUB FISUBR FLD FLD1 FLDL2E FLDL2T FLDCW FLDENV  FLDLG2  FLDLN2
                 FLDPI  FLDZ  FMUL  FMULP  FNCLEX FNDISI FNENI FNINIT FNOP FNSAVE
                 FNSTCW FNSTENV FNSTSW FPATAN FPREM FPREM1 FPTAN  FRNDINT  FRSTOR
                 FSAVE  FSCALE  FSETPM  FSIN  FSINCOS FSQRT FST FSTCW FSTENV FSTP
                 FSTSW FSUB FSUBP FSUBR FSUBRP FTST FUCOM  FUCOMP  FUCOMPP  FWAIT
                 FXAM FXCH FXTRACT FYL2X FYL2XP1

  • USACO 3.1 Shaping Regions 形成的区域 解题报告

    这题二话不说, 用map[i][j]表示坐标为i, j的点是什么颜色的.. 很快就写出来了, 但是内存超过了,, 内存最多16MB.
    没办法, 只好另辟思路, 但是在数据压缩方面我又很弱, 就看标程也花了两三天的时间, 今天终于是看懂了..
    用rect记录所有矩形的坐标以及相应的颜色.
    程序具体的步骤如下:

    输入A, B, N. 记录第一个矩形: (0, 0) (A, B), 颜色为1
    接着读入其余的矩形, 设当前是第i个
    对i之前所有的矩形迭代, 此时迭代到的是第j个.
    判断i是否完全包含j, 即: i.x1 >= j.x1 && i.x2 >= j.x2 && i.y1 <= j.y1 && i.y2 >= j.y2..
    若全包围的话, 将第j个矩形删除.
    如果没包围的话, 就判断i会将j拆分成几个矩形, 并将j删除, 再分别拆分的矩形分别放入rect中.

    /*
    LANG: C
    ID: zqy11001
    PROG: rect1
    */
    #include <stdio.h>
    #include <string.h>
    #define MAX 10001
    #define getint(i) scanf(%d, &i)
    #define loop(i, j, k, l)\\
    if(a.i l b.i){\\
     t = a;\\
     t.j = b.k;\\
     tmp[n++] = t;\\
     a.i = b.i;\\
    }
    
    struct rect{
     int t;
     int x1, x2, y1, y2;
    }rect[MAX];
    int rr;
    int color[2500];
    
    int func(struct rect a, const struct rect b, struct rect *tmp)
    {
     int n;
     struct rect t;
     if(b.x1 >= a.x2 || b.x2 <= a.x1 || b.y1 >= a.y2 || b.y2 <= a.y1){
     return 0;
     }
     if(b.x1 <= a.x1 && b.x2 >= a.x2 && b.y1 <= a.y1 && b.y2 >= a.y2){
     return -1;
     }
    
     n = 0;
     loop(x1, x2, x1, <=);
     loop(x2, x1, x2, >=);
     loop(y1, y2, y1, <=);
     loop(y2, y1, y2, >=);
     return n;
    }
    
    int main(void)
    {
     int n, nr, m;
     int a, b, i, j, k;
     struct rect t[4], cur;
     freopen(rect1.in, r, stdin);
     freopen(rect1.out, w, stdout);
     getint(a);
     getint(b);
     getint(n);
    
     rect[0].x1 = rect[0].y1 = 0;
     rect[0].x2 = a;
     rect[0].y2 = b;
     rect[0].t = 1;
    
     rr = 1;
     for(i = 1; i <= n; i++){
     scanf(%d%d%d%d%d, &rect[rr].x1, &rect[rr].y1, 
     &rect[rr].x2, &rect[rr].y2, &rect[rr].t);
     cur = rect[rr++];
     nr = rr - 1;
     for(j = 0; j < nr; j++){
     m = func(rect[j], cur, t);
     if(!m){
     continue;
     }
     if(m < 0){
     memmove(rect + j, rect + j + 1,
     sizeof(struct rect) * (rr - j - 1));
     j--;
     rr--;
     nr--;
     continue;
     }
     rect[j] = t[--m];
     while(m--){
     rect[rr++] = t[m];
     }
     }
     }
     memset(color, 0, sizeof(color));
     for(i = 0; i < rr; i++){
     color[rect[i].t - 1] += (rect[i].x2 - rect[i].x1) *
     (rect[i].y2 - rect[i].y1);
     }
    
     for(i = 0; i < 2500; i++){
     if(color[i]){
     printf(%d %d\\n, i + 1, color[i]);
     }
     }
     return 0;
    }
  • USACO 3.1 Humble Numbers 丑数 解题报告

    从这一题开始,, 以后题目我就不贴上来了… 自己去看吧..

    这一题开始肯本看不懂,, 后来是反反复复看标程看懂了..

    首先要理解这么一个式子吧(算是式子吧“)

    已经求出了j-1个丑数,, 现在求第j个丑数

    对于每一个素数p乘以一个最小的丑数, 能使积大于第j-1个丑数

    在这些乘积中寻找最小的一个即位第j个丑数.

    用pindex[i]表示对于第i个素数乘以的最小丑数是多少..

    /*
    LANG: C
    ID: zqy11001
    PROG: humble
    */
    #include 
    #include 
    #define MAX 100
    #define getint(i) scanf(%d, &i)
    #define insert(i) hum[count++] = i
    
    long hum[1000001];
    int pindex[MAX];
    int prime[MAX];
    int count;
    
    int main(void)
    {
     int k, n;
     int i;
     int min, m;
     freopen(humble.in, r, stdin);
     freopen(humble.out, w, stdout);
     getint(k);
     getint(n);
     for(i = 0; i < k; i++){
     getint(prime[i]);
     }
    
     insert(1);
     memset(pindex, 0, sizeof(int)*k);
     while(count <= n){
     min = 0x7FFFFFFF;
     for(i = 0; i < k; i++){
     while(prime[i] * hum[pindex[i]] <= hum[count - 1]){
     pindex[i]++;
     }
    
     if(prime[i] * hum[pindex[i]] < min){
     min = prime[i] * hum[pindex[i]];
     m = i;
     }
     }
     insert(min);
     }
    
     printf(%d\\n, hum[n]);
     return 0;
    }
  • USACO 3.1 Score Inflation 总分 解题报告

    Score Inflation

    The more points students score in our contests, the happier we here at the USACO are. We try to design our contests so that people can score as many points as possible, and would like your assistance.

    We have several categories from which problems can be chosen, where a "category" is an unlimited set of contest problems which all require the same amount of time to solve and deserve the same number of points for a correct solution. Your task is write a program which tells the USACO staff how many problems from each category to include in a contest so as to maximize the total number of points in the chosen problems while keeping the total solution time within the length of the contest.

    The input includes the length of the contest, M (1 <= M <= 10,000) (don’t worry, you won’t have to compete in the longer contests until training camp) and N, the number of problem categories, where 1 <= N <= 10,000.

    Each of the subsequent N lines contains two integers describing a category: the first integer tells the number of points a problem from that category is worth (1 <= points <= 10000); the second tells the number of minutes a problem from that category takes to solve (1 <= minutes <= 10000).

    Your program should determine the number of problems we should take from each category to make the highest-scoring contest solvable within the length of the contest. Remember, the number from any category can be any nonnegative integer (0, one, or many). Calculate the maximum number of possible points.

    PROGRAM NAME: inflate
    INPUT FORMAT
    Line 1:  M, N — contest minutes and number of problem classes 
    Lines 2-N+1:  Two integers: the points and minutes for each class

    SAMPLE INPUT (file inflate.in)
    300 4
    100 60
    250 120
    120 100
    35 20

    OUTPUT FORMAT
    A single line with the maximum number of points possible given the constraints.
    SAMPLE OUTPUT (file inflate.out)
    605


    描述
    学生在我们USACO的竞赛中的得分越多我们越高兴。

    我们试着设计我们的竞赛以便人们能尽可能的多得分,这需要你的帮助。

    我们可以从几个种类中选取竞赛的题目,这里的一个"种类"是指一个竞赛题目的集合,解决集合中的题目需要相同多的时间并且能得到相同的分数。你的任务是写一个程序来告诉USACO的职员,应该从每一个种类中选取多少题目,使得解决题目的总耗时在竞赛规定的时间里并且总分最大。输入包括竞赛的时间,M(1 <= M <= 10,000)(不要担心,你要到了训练营中才会有长时间的比赛)和N,"种类"的数目1 <= N <= 10,000。后面的每一行将包括两个整数来描述一个"种类":

    第一个整数说明解决这种题目能得的分数(1 <= points <= 10000),第二整数说明解决这种题目所需的时间(1 <= minutes <= 10000)。你的程序应该确定我们应该从每个"种类"中选多少道题目使得能在竞赛的时间中得到最大的分数。

    来自任意的"种类"的题目数目可能任何非负数(0或更多)。

    计算可能得到的最大分数。

    格式
    PROGRAM NAME: inflate

    INPUT FORMAT:

    (file inflate.in)

    第 1 行: M, N–竞赛的时间和题目"种类"的数目。

    第 2-N+1 行: 两个整数:每个"种类"题目的分数和耗时。

    OUTPUT FORMAT:

    (file inflate.out)

    单独的一行包括那个在给定的限制里可能得到的最大的分数。

    SAMPLE INPUT
    300 4
    100 60
    250 120
    120 100
    35 20
    SAMPLE OUTPUT
    605


    ======================== 华丽的分割线 ========================
      标准的无限背包,, 看<<背包9讲>>

    /*
    LANG: C
    ID: zqy11001
    PROG: inflate
    */
    #include <stdio.h>
    #define getint(i) scanf(%d, &i)
    #define max(a, b) ((a)>(b)?(a):(b))
    
    int f[10001];
    
    int main(void)
    {
     int n, m;
     int i, j, t;
     int a, b;
     freopen(inflate.in, r, stdin);
     freopen(inflate.out, w, stdout);
     getint(m);
     getint(n);
     for(i = 1; i <= n; i++){
     scanf(%d%d, &a, &b);
     for(j = b; j <= 10000; j++){
     t = f[j - b] + a;
     f[j] = max(f[j], t);
     }
     }
     printf(%d\\n, f[m]);
     return 0;
    }
  • USA 3.1 Agri-Net 最短网络 解题报告

    Agri-Net
    Russ Cox
    Farmer John has been elected mayor of his town! One of his campaign promises was to bring internet connectivity to all farms in the area. He needs your help, of course.

    Farmer John ordered a high speed connection for his farm and is going to share his connectivity with the other farmers. To minimize cost, he wants to lay the minimum amount of optical fiber to connect his farm to all the other farms.

    Given a list of how much fiber it takes to connect each pair of farms, you must find the minimum amount of fiber needed to connect them all together. Each farm must connect to some other farm such that a packet can flow from any one farm to any other farm.

    The distance between any two farms will not exceed 100,000.

    PROGRAM NAME: agrinet
    INPUT FORMAT
    Line 1:  The number of farms, N (3 <= N <= 100). 
    Line 2..end:  The subsequent lines contain the N x N connectivity matrix, where each element shows the distance from on farm to another. Logically, they are N lines of N space-separated integers. Physically, they are limited in length to 80 characters, so some lines continue onto others. Of course, the diagonal will be 0, since the distance from farm i to itself is not interesting for this problem. 

    SAMPLE INPUT (file agrinet.in)
    4
    0 4 9 21
    4 0 8 17
    9 8 0 16
    21 17 16 0

    OUTPUT FORMAT
    The single output contains the integer length that is the sum of the minimum length of fiber required to connect the entire set of farms.

    SAMPLE OUTPUT (file agrinet.out)
    28

    描述
    农民约翰被选为他们镇的镇长!他其中一个竞选承诺就是在镇上建立起互联网,并连接到所有的农场。当然,他需要你的帮助。约翰已经给他的农场安排了一条高速的网络线路,他想把这条线路共享给其他农场。为了使花费最少,他想铺设最短的光纤去连接所有的农场。你将得到一份各农场之间连接费用的列表,你必须找出能连接所有农场并所用光纤最短的方案。每两个农场间的距离不会超过100000

    格式
    PROGRAM NAME: agrinet

    INPUT FORMAT:

    (file agrinet.in)

    第一行: 农场的个数,N(3<=N<=100)。

    第二行..结尾: 后来的行包含了一个N*N的矩阵,表示每个农场之间的距离。理论上,他们是N行,每行由N个用空格分隔的数组成,实际上,他们限制在80个字符,因此,某些行会紧接着另一些行。当然,对角线将会是0,因为不会有线路从第i个农场到它本身。

    OUTPUT FORMAT:

    (file agrinet.out)

    只有一个输出,其中包含连接到每个农场的光纤的最小长度。

    SAMPLE INPUT
    4
    0 4 9 21
    4 0 8 17
    9 8 0 16
    21 17 16 0
    SAMPLE OUTPUT
    28



    ======================= 华丽的分割线 =======================
      这一题就是最小生成树的问题, 说来复杂… 自己看数据结构吧..

    /*
    LANG: C
    ID: zqy11001
    PROG: agrinet
    */
    #include <stdio.h>
    #define getint(i) scanf(%d, &i)
    #define MAX 100
    #define INF 1e6
    
    int map[MAX][MAX];
    int visited[MAX];
    int path[MAX];
    
    int main(void)
    {
     int n;
     int i, j, k;
     int min, m, tot = 0;
     freopen(agrinet.in, r, stdin);
     freopen(agrinet.out, w, stdout);
     getint(n);
     for(i = 0; i < n; i++){
     for(j = 0; j < n; j++){
     getint(map[i][j]);
     }
     }
    
     for(i = 0; i < n; i++){
     path[i] = map[0][i];
     }
     visited[0] = 1;
     for(i = 1; i < n; i++){
     min = INF;
     for(j = 0; j < n; j++){
     if(!visited[j] && min > path[j]){
     min = path[j];
     m = j;
     }
     }
     visited[m] = 1;
     tot += min;
     for(j = 0; j < n; j++){
     if(visited[j] == 0 && map[m][j] < path[j]){
     path[j] = map[m][j];
     }
     }
     }
     printf(%d\\n, tot);
     return 0;
    }