Problem:
Max Score: 500 Points

Problem Statement

We have a grid with n rows and 7 columns. We call it a calendar. The cell at i-th row and j-th column is denoted (i, j).

Initially, each cell at (i, j) contains the integer 7i + j - 8, and each cell is white.

Snuke likes painting, so he decided integer m, and did q operations with a calendar.

・In i-th operation, he paint black on the cell in which an integer is written such remainder of dividing by m is a_i.

Please count the number of connected white parts.

Note that if two adjacent cells are white, the cells belong to the same connected part.

Input Format

The input format is following:

n m q
a_1 a_2 ... a_q

Output Format

Print the number of connected part in one line.

Constraints

n ≤ 10^{12}

7n is divisible by m.

1 ≤ q ≤ m ≤ 10^5

0 ≤ a_1 < a_2 < ... < a_q < m

Scoring

Subtask 1 [100 points]

n ≤ 100000.

Subtask 2 [90 points]

m is divisible by 7.

a_{i + 1} - a_i = 1.

Subtask 3 [200 points]

m is divisible by 7.

Subtask 4 [110 points]

There are no additional constraints.

Sample Input 1

7 7 3
1 3 5

Sample Output 1

4

The calendar looks like this:

Sample Input 2

10 14 8
5 6 7 8 9 10 11 12

Sample Output 2

10

The calendar looks like this:

Solution in C# (Mono 4.6.2.0) (judge verdict: Accepted)

using System;
using System.Linq;//リストの使用
using System.Collections.Generic;
class Program
{
static string[] input = Console.ReadLine().Split(' ');
static long n = long.Parse(input[0]);
static long m = long.Parse(input[1]);
static long q = long.Parse(input[2]);
static long r = m;//行数
static long c = 7;//列数
static long[] nums = Array.ConvertAll(Console.ReadLine().Split(' '),long.Parse);
static long numsCount = 0;
static long[] startPosition = new long[2];//スタート座標
static long[,] distances;//最短距離
static Queue<long[]> que = new Queue<long[]>();//幅優先探索用のキュー
static long[,] wallPositions;//壁は1
static long[] VectorArrow = new long[8]{0,1,0,-1,1,0,-1,0};//上下左右に進む為のベクトル
static long islandsCount = 0;//島の数
static long islandsCountFirst = 0;
static long islandsCountSecond = 0;

	static void Main()
	{
		if(m % 7 == 0) r /= 7;

		distances = new long[2*r,c];
		wallPositions = new long[2*r+4,c+2];
  
		for(long i = 0; i < r; i++)
    {
			for(long j = 0; j < c; j++)
			{
				if((7*i+j) % m == nums[numsCount])
				{
					wallPositions[i+1,j+1] = 1;//壁の取得
					numsCount++;
					numsCount %= q;
				}else wallPositions[i+1,j+1] = 0;
			}
    }

    for(long i = 0; i < r+2; i++)//周囲を壁で埋める
    {
      wallPositions[i,0] = 1;
      wallPositions[i,c+1] = 1;
    }
    for(long j = 0; j < c+2; j++)
    {
      wallPositions[0,j] = 1;
      wallPositions[r+1,j] = 1;
    }

		for(long i = 0; i < r; i++)
		{
			for(long j = 0; j < c; j++)
			{
				distances[i,j] = long.MaxValue;//距離を無限と仮定
			}
		}
		
		for(int i = 0; i < r; i++)
		{
			for(int j = 0; j < c; j++)
			{
				if(distances[i,j] == long.MaxValue && wallPositions[i+1,j+1] == 0)
				{
					islandsCount++;
					startPosition[0] = i;
					startPosition[1] = j;
					//Console.WriteLine(i+" "+j+" "+distances[i,j]);
					BFS(startPosition);//幅優先探索
				}
			}
		}

		islandsCountFirst = islandsCount;//１つ目の島
		islandsCount = 0;
		r *= 2;
		numsCount = 0;

		for(long i = 0; i < r; i++)
    {
			for(long j = 0; j < c; j++)
			{
				if((7*i+j) % m == nums[numsCount])
				{
					wallPositions[i+1,j+1] = 1;//壁の取得
					numsCount++;
					numsCount %= q;
				}else wallPositions[i+1,j+1] = 0;
			}
    }
    for(long i = 0; i < r+2; i++)//周囲を壁で埋める
    {
      wallPositions[i,0] = 1;
      wallPositions[i,c+1] = 1;
    }
    for(long j = 0; j < c+2; j++)
    {
      wallPositions[0,j] = 1;
      wallPositions[r+1,j] = 1;
    }

		for(long i = 0; i < r; i++)
		{
			for(long j = 0; j < c; j++)
			{
				distances[i,j] = long.MaxValue;//距離を無限と仮定
			}
		}

		for(int i = 0; i < r; i++)
		{
			for(int j = 0; j < c; j++)
			{
				if(distances[i,j] == long.MaxValue && wallPositions[i+1,j+1] == 0)
				{
					islandsCount++;
					startPosition[0] = i;
					startPosition[1] = j;
					BFS(startPosition);//幅優先探索
				}
			}
		}

		islandsCountSecond = islandsCount;

		r /= 2;
		long a = islandsCountSecond - islandsCountFirst;
		long b = islandsCountFirst - a;
		long aa = n/r;
		//Console.WriteLine(islandsCountFirst + " " + islandsCountSecond);
		Console.WriteLine(a*aa+b);
    
	}

  static void BFS(long[] startPosition)//幅優先探索。引数はスタートの座標。
  {
    que.Enqueue(startPosition);
    
    distances[startPosition[0], startPosition[1]] = 0;//スタート地点までの距離は0
    long poppedMemoX = 0;
    long poppedMemoY = 0;
    while(que.Count > 0)
    {
      poppedMemoX = que.Peek()[0];
      poppedMemoY = que.Peek()[1];
      que.Dequeue();
    
      for(long partnerNum = 0; partnerNum < 4; partnerNum++)//上下左右に進みたい
      {
        long aimX = poppedMemoX+VectorArrow[2*partnerNum];
        long aimY = poppedMemoY+VectorArrow[2*partnerNum+1];
        if(wallPositions[aimX+1, aimY+1] == 1) continue;//壁なら無視
        if(distances[aimX, aimY] != long.MaxValue) continue;//距離が確定済みなら無視
        distances[aimX, aimY] = 1;//距離の加算
        que.Enqueue(new long[2]{aimX, aimY});
      }
    }
      /*
      for(long i = 0; i < r; i++)//各点までの距離の表示
      {
        string answer = "";
        for(long j = 0; j < c; j++)
        {
          if(wallPositions[i+1,j+1] == 1) answer += "#";
          else answer += distances[i,j].ToString();
        }
        Console.WriteLine(answer);
      }
      */

  }
}