C - Triangular Relationship

はじめに

競技プログラミングAtCoder Beginner Contest 108
C - Triangular Relationship
言語はC#
何かあればTwitter→@pirorirori_n712まで

問題

問題文

整数 N,Kが与えられます。
N以下の正の整数の組 (a,b,c)であって、a+b,b+c,c+aがすべて Kの倍数であるようなものの個数を求めてください。 
ただし、a,b,cの順番を入れ替えただけの組も異なるものとして数えます。
また、a,b,cの中に同じものがあっても構いません。

制約

・1≤N,K≤2×10^5
・N,Kは整数である

入力

入力は以下の形式で標準入力から与えられる。

N K

出力

N以下の正の整数の組 (a,b,c)であって、a+b,b+c,c+aがすべてKの倍数であるようなものの個数を出力せよ。

解き方

以下の記事がとても分かり易いです。
pyteyon.hatenablog.com
qiita.com

上の記事が分かり易いので、
ここでは流れを見るだけにとどめます。
解き方の詳しい内容はありません。

備忘録

以下のコードを参考にしています。
atcoder.jp

この問題を解くうえで重要なことは、modの使用です。
問題文の「Kの倍数」という部分に反応してmodの使用を疑います。

次に、
「N以下の正の整数の組 (a,b,c)であって、a+b,b+c,c+aがすべて Kの倍数であるようなもの」
の個数を最終的に答えなければいけないので
どんなものが(a,b,c)の組になり得るかを考えます。

(a,b,c)では考えにくいので、
初めに(a,b)で考えてみます。

ここで、
modの考え方を適用し

・aとbがどちらもKの倍数であること
・Kが偶数であるとき、aとbがa%K=K/2かつb%K=K/2

であることに気づきます。

これは(a,b)が(a,b,c)になってもそのまま適用できるので
このまま実装にうつります。

先ほど、考えた条件のうち

・aとbとcが全てKの倍数であること

はK偶数、奇数どちらでも使えるのでまずこれを入れます。
N以下のKの個数を数えたいので

N以下のKの倍数=N/K;

で出します。

また、出した個数の組み合わせは
当てはめる場所が(a,b,c)と三か所あり
問題文より数の重複が許されるので

aとbとcが全てKの倍数であるときの(a,b,c)の組の数
=(long)Math.Pow(count, 3);

となります。

longへのキャストはoverflow防止です。

次に以下の条件を考えます。

Kが偶数であるとき、aとbがa%K=K/2かつb%K=K/2かつc%K=K/2

Kが偶数であるときに適用するので
Kが偶数であるかどうかをまずフィルターします。

        if (K % 2 == 0)
        {
             //処理
        }

次にN以下の整数の中で
Kで割ると余りがK/2になる整数の個数を出します。

Kで割ると余りがK/2になる整数の個数 = (N + (K / 2)) / K;

ここでNに(K/2)を足したものをKで割っていることが
少し混乱するので入力例1で考えてみます。

入力例1

3 2

これをそのまま先ほどの式に入れると以下のようになります。

(N + (K / 2)) / K
=(3 + (2 / 2)) / 2
=4/2
=2

(a,b,c)に入る数はN以下でなければならないはずですが
Kを2で割ったものをNに足したものを
Kで割り、個数を出しています。

4以下の2の倍数は
2と4なので4はNである3を超えてしまいますが
Kを2で割ったときに(K/2)の余りがある数が欲しいので
実際には
2と4ではなく、それぞれから(2/1)を引いた
1と3のことを数えています。

そして、ここでも
出した個数の組み合わせは
当てはめる場所が(a,b,c)と三か所あり
問題文より数の重複が許されるので

Kで割ると余りがK/2になる整数の(a,b,c)の組の数
=(long)Math.Pow(count, 3);


偶数の場合は両方の条件の組の数を足した数、
奇数の場合は初めの条件に当てはまる組の数を出力します。

全体のコード

using System;
using System.Linq;
using System.Collections.Generic;

class Cmondai
{
    static void Main()
    {
        var nk = Console.ReadLine().Split(' ').Select(x => Int64.Parse(x)).ToArray();
        var N = nk[0];
        var K = nk[1];
        var ans = 0L;
        //aとbとcが全てKの倍数である
        var count = N / K;
        ans += (long)Math.Pow(count, 3);
        //Kが偶数であるとき、aとbがa%K=K/2かつb%K=K/2かつc%K=K/2
        if (K % 2 == 0)
        {
            count = (N + (K / 2)) / K;
            ans += (long)Math.Pow(count, 3);
        }
        Console.WriteLine(ans);
    }
}