AtCoder に登録したら解くべき精選過去問 10 問を Pascal で解いてみた


実装リンク集 https://qiita.com/drken/items/6edb1c0542d4c3b7179c
問題一覧 https://abs.contest.atcoder.jp/assignments

|私の実装|記事|
|:--|:--|
|Ruby (私家版)|https://qiita.com/cielavenir/items/c0a45b6b87c411b60b93|
|Swift|https://qiita.com/cielavenir/items/b90a94dce60a620fa2dc|
|C|https://qiita.com/cielavenir/items/ee1e47b844d05dcfc66e|
|VB.Net|https://qiita.com/cielavenir/items/7ddf5e9bac02daf72159|
|Pascal|https://qiita.com/cielavenir/items/530270ac4affca435442|
|Perl|https://qiita.com/cielavenir/items/4d16ba1be4ad6847a914|
|MoonScript/Lua|https://qiita.com/cielavenir/items/6553531e230f39cd6a3d|

PascalはおそらくIOが速い？言語で、A/B問題最速コードはPascalであることが多いです。0msも狙えます。

# 解答

Pascalの文法はVBに近い雰囲気です。

## 例題 PracticeA

https://practice.contest.atcoder.jp/tasks/practice_1

readで読み込めます。

```pascal:0.pas
program practiceA;
uses SysUtils;
var
    a,b,c: integer;
    s: string;
begin
    read(a); // readlnにする必要はない
    read(b);
    readln(c);
    readln(s);
    writeln(IntToStr(a+b+c)+' '+s);
end.
```

## 第１問 ABC086A Product

https://abc086.contest.atcoder.jp/tasks/abc086_a

Pascalにも3項演算子っぽいものはありますが、短絡しません。

```pascal:1.pas
program ABC086A;
uses StrUtils;
var
    a,b: integer;
begin
    read(a);
    read(b);
    writeln(ifThen(a*b mod 2>0,'Odd','Even'));
end.
```

## 第２問 ABC081A Placing Marbles

https://abc081.contest.atcoder.jp/tasks/abc081_a

Pascalの文字列は1-indexedです。
あと、forやifは全部複文形式で書いていますが、1文だけの場合はbegin-endで囲む必要はありませんので好みでどうぞ。

```pascal:2.pas
program ABC081A;
var
    s: string;
    c,i: integer;
begin
    read(s);
    c:=0;
    for i:=1 to 3 do begin
        if s[i]='1' then begin
            c:=c+1;
        end;
    end;
    writeln(c);
end.
```

## 第３問 ABC081B Shift only

https://abc081.contest.atcoder.jp/tasks/abc081_b

arrの各要素に対し2で割ることが出来た回数の最小値です。
INF値として`1<<29`が使われていますが、2倍してオーバーフローしない中で簡潔に書ける数として競技プログラミングではよく使われます。

Pascalでは、整数除算はdiv、剰余はmodです。

```pascal:3.pas
program ABC081B;
var
    i,n,x,r,r0: longint;
    arr: array of integer;
begin
    r:=1<<29;
    read(n);
    SetLength(arr,n);
    for i:=0 to n-1 do begin
        read(arr[i]);
    end;
    for i:=0 to n-1 do begin
        r0:=0;
        x:=arr[i];
        while x mod 2 < 1 do begin
            r0:=r0+1;
            x:=x div 2;
        end;
        if r>r0 then begin
            r:=r0;
        end;
    end;
    writeln(r);
end.
```

## 第４問 ABC087B Coins

https://abc087.contest.atcoder.jp/tasks/abc087_b

500円玉と100円玉の枚数を全探索します。

```pascal:4.pas
program ABC087B;
var
    a,b,c,x,i,j,k,r: integer;
begin
    read(a);
    read(b);
    read(c);
    read(x);
    r:=0;
    for i:=0 to x div 500 do begin
        for j:=0 to (x-500*i) div 100 do begin              k:=x-500*i-100*j;
            if (k mod 50=0) and (c>=k div 50) and (a>=i) and (b>=j) then begin
                r:=r+1;
            end;
        end;
    end;
    writeln(r);
end.
```

## 第５問 ABC083B Some Sums

https://abc083.contest.atcoder.jp/tasks/abc083_b

変数sは各i(j)を10で割れるだけ割って、その間に出た余りの和です。

```pascal:5.pas
program ABC083B;
var 
    n,a,b,r,i,j,s: integer;
begin
    read(n);
    read(a);
    read(b);
    r:=0;
    for i:=1 to n do begin
        s:=0;
        j:=i;
        while j>0 do begin
            s:=s+(j mod 10);
            j:=j div 10;
        end;
        if (a<=s) and (s<=b) then begin
            r:=r+i;
        end;
    end;
    writeln(r);
end.
```

## 第６問 ABC088B Card Game for Two

https://abc088.contest.atcoder.jp/tasks/abc088_b

通常の配列にはソートが実装されていないため、TFPGListを使う必要があります。つらい…

降順でソートしたら、符号を切り替えながら足しこんでいきます。

```pascal:6.pas
program ABC088B;
{$mode Delphi}
uses SysUtils,fgl;

(*
procedure reverse(var a:TFPGList<longint>;start:longint;size:longint);
var
    en,i:longint;
    z:longint;
begin
    en:=start+size-1;
    for i:=0 to trunc(size/2-1) do begin
        z:=a[start+i];
        a[start+i]:=a[en-i];
        a[en-i]:=z;
    end;
end;
*)

function intcompare(n1,n2:longint):longint;
begin
    result:=n2-n1;
end;

var
    n,i,r,t: longint;
    arr: TFPGList<longint>;
begin
    read(n);
    arr:=TFPGList<longint>.Create();
    for i:=0 to n-1 do begin
        read(r);
        arr.Add(r);
    end;
    arr.Sort(@intcompare);
    // reverse(arr,0,arr.Count);
    r:=0;
    t:=1;
    for i:=0 to n-1 do begin
        r:=r+t*arr[i];
        t:=-t;
    end;
    writeln(r);
end.
```

## 第７問 ABC085B Kagami Mochi

https://abc085.contest.atcoder.jp/tasks/abc085_b

```pascal:7.pas
program ABC085B;
{$mode Delphi}
uses SysUtils,fgl;
var
    n,i,r: longint;
    arr: TFPGMap<longint,integer>;
begin
    read(n);
    arr:=TFPGMap<longint,integer>.Create();
    for i:=0 to n-1 do begin
        read(r);
        // arr.AddOrSetData(r,1); // AtCoderでは使用不可
        arr.Remove(r);
        arr.Add(r,1);
    end;
    writeln(arr.Count);
end.
```

## 第８問 ABC085C Otoshidama

https://abc085.contest.atcoder.jp/tasks/abc085_c

1000円札と5000円札の枚数を全探索します。

exitはプログラム終了ではなく関数からリターンする意味になります。
https://www.freepascal.org/docs-html/rtl/system/exit.html

```pascal:8.pas
program ABC085C;
uses SysUtils;
var
    n,y,i,j,k: integer;
begin
    read(n);
    read(y);
    for i:=0 to n do begin
        for j:=0 to n-i do begin
            k:=n-i-j;
            if i*1000+j*5000+k*10000=y then begin
                writeln(IntToStr(k)+' '+IntToStr(j)+' '+IntToStr(i));
                exit;
            end;
        end;
    end;
    writeln('-1 -1 -1');
end.
```

## 第９問 ABC049C Daydream

https://abc049.contest.atcoder.jp/tasks/arc065_a

Substringはcopyです。文字列長をチェックする必要はありません。

```pascal:9.pas
program ABC049C;
uses StrUtils;
var
    T: array[0..3] of string = ('dream','dreamer','erase','eraser');
    s: string;
    i,c,l,k: integer;
begin
    for i:=0 to 3 do begin
        T[i]:=ReverseString(T[i]);
    end;
    readln(s);
    s:=ReverseString(s);
    c:=0;
    l:=Length(s);
    while c<l do begin
        k:=-1;
        for i:=0 to 3 do begin
            if copy(s,c+1,Length(T[i]))=T[i] then begin
                k:=Length(T[i]);
            end;
        end;
        if k<0 then begin
            writeln('NO');
            exit;
        end;
        c:=c+k;
    end;
    writeln('YES');
end.

```

## 第10問 ABC086C Traveling

https://abc086.contest.atcoder.jp/tasks/arc089_a

dx+dyがdt以下かつdtとの偶奇が一致。

```pascal:10.pas
program ABC086C;
var
    i,n,t,x,y: integer;
    t0,x0,y0,dt,dx,dy: integer;
begin
    read(n);
    t:=0;
    x:=0;
    y:=0;
    for i:=1 to n do begin
        read(t0);
        read(x0);
        read(y0);
        dt:=t0-t;
        dx:=x0-x;
        dy:=y0-y;
        if (dx+dy>dt) or ((dt-dx-dy) mod 2>0) then begin
            writeln('No');
            exit;
        end;
        t:=t0;
        x:=x0;
        y:=y0;
    end;
    writeln('Yes');
end.
```