[USACO精选] 第一章 数值计算

好不容易坑来了传说中的USACO精选,近100题我要是能做完就哈哈哈哈了…继今天学并查集连番受挫之后,决定写一写基础题。

#0 负二进制 2014-01-10

其实是想到就会做,不想到就不会做的题,数学渣渣在此,赶紧承认自己看了解题0 0……其实我自己对于负数的mod不是很熟…如果考场上出这种东西自己开个exam.pas弄几个mod负数div负数不就摸索出来了么…

(其实我最开始的想法是,按正数除,除出来一个2^(2k-1)的就当成(-2)^2k+(-2)^(2k-1))

program tyvj_p1022;
var a:array[1..10000] of integer;
    x,i,t:longint;
begin
  readln(x);
  if x=0 then
    begin
      writeln(0);
      halt;
    end;
  t:=0;
  while x<>0 do
    begin
      inc(t);
      a[t]:=x mod (-2);
      if a[t]<0 then
        begin
          a[t]:=a[t]+2;
          x:=x-2;
        end;
      x:=x div (-2);
    end;
  for i:=t downto 1 do
    write(a[i]);
end.
负二进制


#1 数的幂次 2014-01-10

一开始还脑残在想这题是不是不用快速幂啊纯模拟啊…结果,写的快速幂+高精度,自己的机器都超时运作了…话说这题被坑了,我拿到的题目上写着答案不超过15000个字符的,结果我201个好久还以为是integer太小了,开成了longint,后来直接qword了… 后来数组开50000就over了…

不写不知道一写吓一跳噜,写快速幂+高精度要注意:(1)高精度自乘(本程序中采用ti数组)不要一脑残就以为是2在自己乘啊!(2)高精度a[i+j]:=a[i+j-1] div 10啊不要一脑残直接inc(a[i+j])…程序可优化的空间就是,写了两段高精度乘,其实可以弄成两个参数而不要再写一遍的…

program cruel1;
var a,ti:array[0..50000] of qword;
    node:array[0..20] of boolean;
    n,p,t,i,tn,t0:longint;
procedure work_self_times;
var c:array[0..50000] of qword;
    i,j,t:longint;
begin
  fillchar(c,sizeof(c),0);
  for i:=1 to ti[0] do
    for j:=1 to ti[0] do
      begin
        c[i+j-1]:=c[i+j-1]+ti[i]*ti[j];
        if c[i+j-1]>9 then
          begin
            c[i+j]:=c[i+j]+c[i+j-1] div 10;
            c[i+j-1]:=c[i+j-1] mod 10;
          end;
      end;
  t:=2*ti[0];
  while c[t]=0 do dec(t);
  c[0]:=t;
  ti:=c;
end;

procedure times;
var c:array[0..50000] of qword;
    i,j,t:longint;
begin
  fillchar(c,sizeof(c),0);
  for i:=1 to a[0] do
    for j:=1 to ti[0] do
      begin
        c[i+j-1]:=c[i+j-1]+a[i]*ti[j];
        if c[i+j-1]>9 then
          begin
            c[i+j]:=c[i+j]+c[i+j-1] div 10;
            c[i+j-1]:=c[i+j-1] mod 10;
          end;
      end;
  t:=2*ti[0];
  while c[t]=0 do dec(t);
  c[0]:=t;
  a:=c;
end;
begin
  readln(n,p);
  t:=1;
  while p<>0 do
    begin
      if p mod 2=1 then node[t]:=true;
      p:=p div 2;
      inc(t);
    end;
  fillchar(a,sizeof(a),0); a[1]:=1; a[0]:=1;
  fillchar(ti,sizeof(ti),0);
  t0:=1;tn:=n;
  while tn<>0 do
    begin
      ti[t0]:=tn mod 10;
      tn:=tn div 10;
      inc(t0);
    end;
  ti[0]:=t0-1;
  for i:=1 to t do
    begin
      if node[i]=true then times;
      work_self_times;
    end;
  t:=15000;
  while a[t]=0 do dec(t);
  for i:=t downto 1 do
    write(a[i]);
end.
数的幂次

#2 分数变小数 2014-01-11

又脑残去搜题解了,结果看到很多大神的博客都说这题神坑,我还以为这题有多么的奇葩… 其实就是除法啦,第一次出错后还莫名其妙想了个要写链表的方法…(那方法其实是错的,但是话说上一次写链表是不知道多少年前了,要练习一下。)

x是商,x0是余数(多余的,可以不用),mark标记余数是否出现过。output1用于无循环的小数的输出,output2用于循环小数的输出。

其实有点虚,目测了一下答案是对的,但是数据7和8实在太长了…

program usaco_3;
var n,d,z,t,i:longint;
    x,x0:array[0..200000] of longint;
    mark:array[0..100000] of longint;
procedure output1;
var i:longint;
begin
  for i:=0 to t do
    write(x[i]);
  halt;
end;
procedure output2(l,r:longint);
var i:longint;
begin
  for i:=1 to t do
    begin
      if i=l+1 then write('(');
      write(x[i]);
      if i=r then write(')');
    end;
  halt;
end;

begin
  readln(n,d);
  z:=n div d;
  n:=n mod d;
  write(z,'.');
  if n=0 then
    begin
      write('0');
      halt;
    end;
  t:=0;
  for i:=1 to 100000 do mark[i]:=-1;
  mark[n]:=0;
  while true do
    begin
      inc(t);
      x0[t]:=n;
      n:=n*10;
      x[t]:=n div d;
      n:=n mod d;
      if n=0 then output1;
      if (mark[n]<>-1) then
        output2(mark[n],t)
      else
        mark[n]:=t;
    end;
end.
分数变小数

#3 丑数 2014-01-12

之前有两个程序是失败的,两个都是枚举list中的数据而不是p中的素数,导致慢的要死,要知道k的范围是[1,100],n的范围是[1,100000]…第二个稍微加了个小优化,用p0记录以免重复乘。然后默默去看题解…(啊啊啊你怎么能这么不独立呢!)于是开始枚举素数,用p0记录。但是第12个数据点的n=100000貌似还是很慢,这题目前没找到到oj可以测评(没去找…),去网上拉了个题解复制下来看看貌似第12点都超级慢,那就先搁着吧,等我USACO的training做到Chapter 3了去提交一下就知道了…

BTW快排可以不用写,我拿到的翻译里面没写输入的时候是有序的所以我自作多情地写了一个… T T

最终的:

program usaco_3;
var k,n,i,j,l,t,t0:dword;
    p,p0:array[1..100] of longint;
    list:array[0..100000] of dword;
procedure qsort(l,r:longint);
var i,j,mid,t:longint;
begin
  i:=l;j:=r;mid:=p[(l+r) div 2];
  repeat
    while p[i]<mid do inc(i);
    while p[j]>mid do dec(j);
    if i<=j then
      begin
        t:=p[i];p[i]:=p[j];p[j]:=t;
        inc(i);dec(j);
      end;
  until i>j;
  if i<r then qsort(i,r);
  if j>l then qsort(l,j);
end;

begin
  readln(k,n);
  for i:=1 to k do
    read(p[i]);
  qsort(1,k);
  list[1]:=1;
  for i:=2 to n+1 do
    begin
      t:=maxlongint;
      for j:=1 to k do
        begin
          while p[j]*list[p0[j]]<=list[i-1] do inc(p0[j]);
          if p[j]*list[p0[j]]<t then t:=p[j]*list[p0[j]];
        end;
      list[i]:=t;
    end;
  writeln(list[n+1]);
end.
丑数

前两个失败的:

program usaco_3;
var k,n,i,j,t,t0:longint;
    p:array[1..100] of longint;
    list:array[1..100000] of longint;
procedure qsort(l,r:longint);
var i,j,mid,t:longint;
begin
  i:=l;j:=r;mid:=p[(l+r) div 2];
  repeat
    while p[i]<mid do inc(i);
    while p[j]>mid do dec(j);
    if i<=j then
      begin
        t:=p[i];p[i]:=p[j];p[j]:=t;
        inc(i);dec(j);
      end;
  until i>j;
  if i<r then qsort(i,r);
  if j>l then qsort(l,j);
end;

function search(start,xi:longint):longint;
var t,i:longint;
begin
  for i:=1 to k do
    if start*p[i]>xi then
      begin
        t:=start*p[i];
        exit(t);
      end;
end;

begin
  readln(k,n);
  for i:=1 to k do
    read(p[i]);
  qsort(1,k);
  list[1]:=1;
  for i:=2 to n+1 do
    begin
      t:=maxlongint;
      for j:=1 to i-1 do
        begin
          t0:=search(list[j],list[i-1]);
          if t0<t then t:=t0;
        end;
      list[i]:=t;
    end;
  writeln(list[n+1]);
end.
丑数-demo1
program usaco_3;
var k,n,i,j,t,t0:longint;
    p:array[1..100] of longint;
    list,p0:array[1..100000] of longint;
procedure qsort(l,r:longint);
var i,j,mid,t:longint;
begin
  i:=l;j:=r;mid:=p[(l+r) div 2];
  repeat
    while p[i]<mid do inc(i);
    while p[j]>mid do dec(j);
    if i<=j then
      begin
        t:=p[i];p[i]:=p[j];p[j]:=t;
        inc(i);dec(j);
      end;
  until i>j;
  if i<r then qsort(i,r);
  if j>l then qsort(l,j);
end;

function search(start,xi:longint):longint;
var t,i:longint;
begin
  if p0[start]>xi then exit(p0[start]);
  for i:=1 to k do
    if list[start]*p[i]>xi then
      begin
        t:=list[start]*p[i];
        p0[start]:=t;
        exit(t);
      end;
end;

begin
  readln(k,n);
  for i:=1 to k do
    read(p[i]);
  qsort(1,k);
  list[1]:=1;
  for i:=2 to n+1 do
    begin
      t:=maxlongint;
      for j:=1 to i-1 do
        begin
          t0:=search(j,list[i-1]);
          if t0<t then t:=t0;
        end;
      list[i]:=t;
    end;
  writeln(list[n+1]);
end.
丑数-demo2
原文地址:https://www.cnblogs.com/Sky-Grey/p/3514514.html