みんなのプロコン 2019

考察

みんなのプロコン 2019の参加記録.

B - Path

4つの街と3つの道が与えられる. 一筆書で全ての街を訪れることができるか.

制約

同じ街の対の間を結ぶ道は複数存在しない どの2つの街の間も、道を何本か通ることで行き来することができる

より, 全ての街を訪れることは可能であることがわかる. このとき道と街の組み合わせしてありうるのは以下の2パターン.

A
B

一筆書き出来るのはB.
Aは1つの街から3本以上の道が存在する場合なので, 街から生えている道の本数で判定すればいい.

解答

use std::io;


fn main() {
    let mut a = 0;
    let mut b = 0;
    let mut c = 0;
    let mut d = 0;
    for _ in 0..3 {
        let ab = read::<usize>();
        for i in ab {
            match i {
                1 => a += 1,
                2 => b += 1,
                3 => c += 1,
                4 => d += 1,
                _ => unreachable!(),
            }
        }
    }
 
    if a > 2 || b > 2 || c > 2 || d > 2 {
        println!("NO");
    } else {
        println!("YES");
    }
}

C - When I hit my pocket...

手持ちのビスケット1枚, 0円の状態から

  • 持っているビスケットを増やす
  • ビスケット1枚をA円に交換
  • 1円をビスケットB枚の交換

以上の操作を好きな順にkk回行ってビスケットの枚数を最大化する. なお虚無からビスケットを生成できるらしい.

ビスケット → 円 → ビスケットの両替には2ターン消費するので, 2枚以上の利益がなければ愚直にビスケットを増やすのと変わらない.

なので BA<=2B-A <= 2の場合にはビスケットを増やす操作だけ行うのが最善.

BA>2B-A>2の場合には, ビスケット→ 円→ ビスケット の操作でビスケットを(BA)(B - A)枚増産できる. 最終的に円を持っていても意味がないので, この一連の操作は操作は同じ回数行いたい.

簡単のために, ビスケットを0枚もっている状態からk+1k + 1回の操作を行えるとする.
アプローチとしては,

  1. A枚たまるまでビスケットを増やす
  2. 残りk+1Ak + 1 - A回の操作で両替を繰り返す

手順2は(k+1a)/2\lfloor(k+1-a)/2\rfloor回行うことができる. 偶奇によっては操作回数が一回あまるが, ここでビスケット→ 円の両替をしても仕方がないのでビスケットを1枚増やす.

解答

use std::io;


fn main() {
    let (k, a, b) = {
        let i = read::<u64>();
        (i[0], i[1], i[2])
    };

    if a >= b || b - a <= 1{
        println!("{}", k + 1);
        return;
    }

    let ans: u64 = if (k + 1 - a) % 2 == 0 {
        (b - a) * (k + 1 - a) / 2 + a
    } else {
        (b - a) * (k - a) / 2 + a + 1
    };

    println!("{}", ans);
}

所感

考察を詰めきらずにふわふわした状態でB,Cをときがち. 論文が一段落したので, しばらくはこれを書いてから実装するくらいの気持ちで精進してみる.

Commits

2021-01-30 22:18:1735b550aecopy md
commit 35b550ae83af4efaeadf33471c8ca8a32c1079c8
Author: koka &&gt;
Date:   Sat Jan 30 22:18:17 2021 +0900

  copy md

diff --git a/_posts/2019-02-09-minpro2019.md b/_posts/2019-02-09-minpro2019.md
new file mode 100644
index 0000000..eb1daad
--- /dev/null
+++ b/_posts/2019-02-09-minpro2019.md
@@ -0,0 +1,148 @@
+---
+title: みんなのプロコン 2019
+date: 2019-02-09
+categories:
+- Competitive Programming
+tags:
+- AtCoder
+- TODO
+description: 考察
+---
+
+みんなのプロコン 2019の参加記録.
+
+## [B - Path](https://atcoder.jp/contests/yahoo-procon2019-qual/tasks/yahoo_procon2019_qual_b)
+
+4つの街と3つの道が与えられる. 一筆書で全ての街を訪れることができるか.
+
+制約
+&gt; 同じ街の対の間を結ぶ道は複数存在しない
+&gt; どの2つの街の間も、道を何本か通ることで行き来することができる
+
+より, 全ての街を訪れることは可能であることがわかる.
+このとき道と街の組み合わせしてありうるのは以下の2パターン.
+
+&lt;div class="graph-wrapper"&gt;
+&lt;div&gt;
+&lt;div class="graph graph1"&gt;
+  &lt;div class="edge" /&gt;
+  &lt;div class="node none" /&gt;
+  &lt;div class="edge" /&gt;
+&lt;/div&gt;
+&lt;div class="graph"&gt;
+  &lt;div class="edge" /&gt;
+  &lt;div class="node" /&gt;
+  &lt;div class="edge cross vertical" /&gt;
+&lt;/div&gt;
+&lt;div class="label"&gt;A&lt;/div&gt;
+&lt;/div&gt;
+
+&lt;div&gt;
+&lt;div class="graph graph2"&gt;
+  &lt;div class="edge" /&gt;
+  &lt;div class="node" /&gt;
+  &lt;div class="edge" /&gt;
+&lt;/div&gt;
+&lt;div class="graph"&gt;
+  &lt;div class="edge" /&gt;
+  &lt;div class="node" /&gt;
+  &lt;div class="edge vertical" /&gt;
+&lt;/div&gt;
+&lt;div class="label"&gt;B&lt;/div&gt;
+&lt;/div&gt;
+
+&lt;/div&gt;
+
+一筆書き出来るのはB.  
+Aは1つの街から3本以上の道が存在する場合なので, 街から生えている道の本数で判定すればいい.
+
+### 解答
+
+\```rust
+use std::io;
+
+
+fn main() {
+    let mut a = 0;
+    let mut b = 0;
+    let mut c = 0;
+    let mut d = 0;
+    for _ in 0..3 {
+        let ab = read::&lt;usize&gt;();
+        for i in ab {
+            match i {
+                1 =&gt; a += 1,
+                2 =&gt; b += 1,
+                3 =&gt; c += 1,
+                4 =&gt; d += 1,
+                _ =&gt; unreachable!(),
+            }
+        }
+    }
+ 
+    if a &gt; 2 || b &gt; 2 || c &gt; 2 || d &gt; 2 {
+        println!("NO");
+    } else {
+        println!("YES");
+    }
+}
+\```
+
+## [C - When I hit my pocket...](https://atcoder.jp/contests/yahoo-procon2019-qual/tasks/yahoo_procon2019_qual_c)
+
+手持ちのビスケット1枚, 0円の状態から
+
+- 持っているビスケットを増やす
+- ビスケット1枚をA円に交換
+- 1円をビスケットB枚の交換
+
+以上の操作を好きな順に$k$回行ってビスケットの枚数を最大化する. なお虚無からビスケットを生成できるらしい.
+
+ビスケット → 円 → ビスケットの両替には2ターン消費するので, 2枚以上の利益がなければ愚直にビスケットを増やすのと変わらない.
+
+なので $B-A &lt;= 2$の場合にはビスケットを増やす操作だけ行うのが最善.  
+
+$B-A&gt;2$の場合には, ビスケット→ 円→ ビスケット の操作でビスケットを$(B - A)$枚増産できる. 最終的に円を持っていても意味がないので, この一連の操作は操作は同じ回数行いたい.  
+
+簡単のために, ビスケットを0枚もっている状態から$k + 1$回の操作を行えるとする.  
+アプローチとしては,
+
+1. A枚たまるまでビスケットを増やす
+2. 残り$k + 1 - A$回の操作で両替を繰り返す
+
+手順2は$\lfloor(k+1-a)/2\rfloor$回行うことができる. 偶奇によっては操作回数が一回あまるが,
+ここでビスケット→ 円の両替をしても仕方がないのでビスケットを1枚増やす.
+
+### 解答
+
+\```rust
+use std::io;
+
+
+fn main() {
+    let (k, a, b) = {
+        let i = read::&lt;u64&gt;();
+        (i[0], i[1], i[2])
+    };
+
+    if a &gt;= b || b - a &lt;= 1{
+        println!("{}", k + 1);
+        return;
+    }
+
+    let ans: u64 = if (k + 1 - a) % 2 == 0 {
+        (b - a) * (k + 1 - a) / 2 + a
+    } else {
+        (b - a) * (k - a) / 2 + a + 1
+    };
+
+    println!("{}", ans);
+}
+\```
+
+
+## 所感
+
+考察を詰めきらずにふわふわした状態でB,Cをときがち. 
+論文が一段落したので, しばらくはこれを書いてから実装するくらいの気持ちで精進してみる.
+