Problem:
Score : 400 points

Problem Statement

Given is a positive integer N.

Find the number of pairs (A, B) of positive integers not greater than N that satisfy the following condition:

When A and B are written in base ten without leading zeros, the last digit of A is equal to the first digit of B, and the first digit of A is equal to the last digit of B.

Constraints

1 \leq N \leq 2 \times 10^5

All values in input are integers.

Input

Input is given from Standard Input in the following format:

N

Output

Print the answer.

Sample Input 1

25

Sample Output 1

17

The following 17 pairs satisfy the condition: (1,1), (1,11), (2,2), (2,22), (3,3), (4,4), (5,5), (6,6), (7,7), (8,8), (9,9), (11,1), (11,11), (12,21), (21,12), (22,2), and (22,22).

Sample Input 2

1

Sample Output 2

1

Sample Input 3

100

Sample Output 3

108

Sample Input 4

2020

Sample Output 4

40812

Sample Input 5

200000

Sample Output 5

400000008

Solution in C# (Mono 4.6.2.0) (judge verdict: Wrong Answer)

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

namespace Practice
{
    class Program
    {
        static void Main(string[] args)
        {
            var sw = new System.IO.StreamWriter(Console.OpenStandardOutput()) { AutoFlush = false };
            Console.SetOut(sw);
            Solve();

            Console.Out.Flush();
        }
        private const int MOD = 1000000007;
        private const int MAX = 1000001;
        static long[] fac = new long[MAX];
        static long[] finv = new long[MAX];
        static long[] inv = new long[MAX];

        private static string szN;
        private static int n;

        static void Solve()
        {
            n = Input.NextInt();
            szN = n.ToString();
            int keta = n.ToString().Length;
            long ans = 0;

            // 両方一桁
            for(int i=1;i<=9;++i)
            {
                if( i <= n) { ans++; }
            }
            // 片方が一桁
            for(int i=1;i<=9;++i)
            {
                long tmp = 0;
                int s = 0;
                while(2+s<=keta)
                {
                    tmp += CountA(i,i, s);
                    s++;
                }
                ans += tmp * 2;
            }
            // 両方二桁以上
            for(int i=1;i<=9;++i)
            {
                for(int j=1;j<=9;++j)
                {
                    int s = 0;
                    while(2+s <= keta)
                    {
                        int t = 0;
                        while(2+t<=keta)
                        {
                            ans += Count(i, j, s, t);
                            t++;
                        }

                        s++;
                    }
                }
            }

            Console.WriteLine(ans);
        }

        // 片方一桁i???i ?はs個
        private static long CountA(int i,int j, int s)
        {
            // 小さい桁
            if( 2+s < szN.Length)
            {
                return pow(10, s);
            }
            else// 同一桁
            {
                int n0 = szN[0] - '0';
                if( i < n0)
                {
                    return pow(10, s);
                }else if( i > n0)
                {
                    return 0;
                }
                else
                {
                    // i000...jからi999...jまであるぞ ijの間にs子
                    int min = GetInt(i, j, s, 0);
                    int max = GetInt(i, j, s, 9);
                    if( min > n) { return 0; }
                    else if( max <= n)
                    {
                        return pow(10, s);// ありえんが
                    }
                    else
                    {
                        int last = szN[szN.Length - 1] - '0';
                        var ans = GetIntHalf();
                        if( j > last)
                        {
                            ans = Math.Max(0, ans - 1);
                        }
                        return ans;
                    }
                }
            }
        }
        private static int GetIntHalf()
        {
            var sb = new StringBuilder();
            for(int i=1;i<szN.Length-1;++i)
            {
                sb.Append(szN[i]);
            }
            return int.Parse(sb.ToString());
        }
        private static int GetInt(int i, int j, int s, int num)
        {
            var sb = new StringBuilder();
            sb.Append(i);
            for(int x=0;x<s;++x)
            {
                sb.Append(num);
            }
            sb.Append(j);
            return int.Parse(sb.ToString());
        }
        private static long Count(int i, int j, int s, int t)
        {
            // ただしn以下が
            return CountA(i,j, s) * CountA(j,i, t);
        }


#region よく使う便利関数

        private static Dictionary<long, int> Factorize(long n)
        {
            var dic = new Dictionary<long, int>();

            for (long i = 2; i * i <= n; ++i)
            {
                while (n % i == 0)
                {
                    if (!dic.ContainsKey(i))
                    {
                        dic.Add(i, 0);
                    }
                    dic[i]++;
                    n /= i;
                }

            }

            if (n != 1)
            {
                dic.Add(n, 1);
            }
            return dic;
        }
        static void COMinit()
        {
            fac[0] = fac[1] = 1;
            finv[0] = finv[1] = 1;
            inv[1] = 1;
            for (int i = 2; i < MAX; i++)
            {
                fac[i] = fac[i - 1] * i % MOD;
                inv[i] = MOD - inv[MOD % i] * (MOD / i) % MOD;
                finv[i] = finv[i - 1] * inv[i] % MOD;
            }
        }

        // 二項係数計算
        static long COM(long n, long k)
        {
            if (n < k) return 0;
            if (n < 0 || k < 0) return 0;
            return fac[n] * (finv[k] * finv[n - k] % MOD) % MOD;
        }

        static class Input
        {
            static char[] separator = { ' ' };
            public static bool IsEof { get; set; }
            static Queue<string> q { get; set; }

            static Input()
            {
                IsEof = false;
                q = new Queue<string>();
            }

            /// <summary>
            /// 入力予約
            /// </summary>
            /// <param name="items"></param>
            public static void SetText(IEnumerable<string> items)
            {
                foreach (var item in items)
                {
                    SetText(item);
                }
            }

            /// <summary>
            /// 入力予約
            /// </summary>
            /// <param name="s"></param>
            /// <returns></returns>
            public static bool SetText(string s)
            {
                if (s == null) return false;

                foreach (var elem in s.Trim().Split(separator, StringSplitOptions.RemoveEmptyEntries))
                {
                    q.Enqueue(elem);
                }

                return true;
            }

            /// <summary>
            /// 内部queueに入力からの値をsplitして格納する
            /// </summary>
            /// <returns></returns>
            static bool read()
            {
                var s = Console.ReadLine();
                if (s == null) return false;

                foreach (var elem in s.Trim().Split(separator, StringSplitOptions.RemoveEmptyEntries))
                {
                    q.Enqueue(elem);
                }

                if (!q.Any()) return read();

                return true;
            }

            /// <summary>
            /// 次のstringを一つ読み込む
            /// </summary>
            /// <returns></returns>
            public static string Next()
            {
                if (!q.Any())
                {
                    if (!read())
                    {
                        IsEof = true;
                        return "";
                    }
                }

                return q.Dequeue();
            }

            public static int NextInt() => int.Parse(Next());
            public static long NextLong() => long.Parse(Next());
            public static double NextDouble() => double.Parse(Next());

            public static List<string> Next(int n) => Enumerable.Range(0, n).Select(_ => Next()).ToList();
            public static List<int> NextInt(int n) => Next(n).Select(x => int.Parse(x)).ToList();
            public static List<long> NextLong(int n) => Next(n).Select(x => long.Parse(x)).ToList();
            public static List<double> NextDouble(int n) => Next(n).Select(x => double.Parse(x)).ToList();

            public static List<string> NextLine() => Console.ReadLine().Trim().Split(separator, StringSplitOptions.RemoveEmptyEntries).ToList();
            public static List<int> NextIntLine() => NextLine().Select(x => int.Parse(x)).ToList();
            public static List<long> NextLongLine() => NextLine().Select(x => long.Parse(x)).ToList();
            public static List<double> NextDoubleLine() => NextLine().Select(x => double.Parse(x)).ToList();
        }
        private static bool isPrime(long x)
        {
            if (x == 2) { return true; }
            if (x < 2 || x % 2 == 0) { return false; }
            long i = 3;
            while (i * i <= x)
            {
                if (x % i == 0) { return false; }
                i = i + 2;
            }
            return true;
        }
        private static long lcm(long x, long y)
        {
            return x / gcd(x, y) * y;
        }
        private static long gcd(long x, long y)
        {
            return y > 0 ? gcd(y, x % y) : x;
        }
        private static long pow(long x, long n)
        {
            if (n == 0) { return 1; }
            long res = pow(x * x % MOD, n / 2);
            if (n % 2 == 1)
            {
                res = res * x % MOD;
            }
            return res;
        }
        private static void Swap<T>(ref T x, ref T y)
        {
            T t = x;
            x = y;
            y = t;
        }

        /// <summary>
        /// 指定した値以上の先頭のインデクスを返す
        /// </summary>
        /// <typeparam name="T">比較する値の型</typeparam>
        /// <param name="arr">対象の配列（※ソート済みであること）</param>
        /// <param name="start">開始インデクス [inclusive]</param>
        /// <param name="end">終了インデクス [exclusive]</param>
        /// <param name="value">検索する値</param>
        /// <param name="comparer">比較関数(インターフェイス)</param>
        /// <returns>指定した値以上の先頭のインデクス</returns>
        public static int LowerBound<T>(IReadOnlyList<T> arr, int start, int end, T value, IComparer<T> comparer)
        {
            int low = start;
            int high = end;
            int mid;
            while (low < high)
            {
                mid = ((high - low) >> 1) + low;
                if (comparer.Compare(arr[mid], value) < 0)
                    low = mid + 1;
                else
                    high = mid;
            }
            return low;
        }

        //引数省略のオーバーロード
        public static int LowerBound<T>(IReadOnlyList<T> arr, T value) where T : IComparable
        {
            return LowerBound(arr, 0, arr.Count, value, Comparer<T>.Default);
        }

        /// <summary>
        /// 指定した値より大きい先頭のインデクスを返す
        /// </summary>
        /// <typeparam name="T">比較する値の型</typeparam>
        /// <param name="arr">対象の配列（※ソート済みであること）</param>
        /// <param name="start">開始インデクス [inclusive]</param>
        /// <param name="end">終了インデクス [exclusive]</param>
        /// <param name="value">検索する値</param>
        /// <param name="comparer">比較関数(インターフェイス)</param>
        /// <returns>指定した値より大きい先頭のインデクス</returns>
        public static int UpperBound<T>(IReadOnlyList<T> arr, int start, int end, T value, IComparer<T> comparer)
        {
            int low = start;
            int high = end;
            int mid;
            while (low < high)
            {
                mid = ((high - low) >> 1) + low;
                if (comparer.Compare(arr[mid], value) <= 0)
                    low = mid + 1;
                else
                    high = mid;
            }
            return low;
        }

        //引数省略のオーバーロード
        public static int UpperBound<T>(IReadOnlyList<T> arr, T value)
        {
            return UpperBound(arr, 0, arr.Count, value, Comparer<T>.Default);
        }
#endregion
    }

    public class DisjointSet
    {
        private int[] rank;
        private int[] p;
        private int[] size;
        public DisjointSet(int n)
        {
            rank = new int[n];
            p = new int[n];
            size = new int[n];
            for (int i = 0; i < n; ++i)
            {
                MakeSet(i);
            }
        }
        public void MakeSet(int x)
        {
            p[x] = x;
            rank[x] = 0;
            size[x] = 1;
        }
        public bool IsSame(int x, int y)
        {
            return FindSet(x) == FindSet(y);
        }
        public void Unite(int x, int y)
        {
            Link(FindSet(x), FindSet(y));
        }
        public void Link(int x, int y)
        {
            if (rank[x] > rank[y])
            {
                p[y] = x;
                size[x] += size[y];
                size[y] = 0;
            }
            else
            {
                p[x] = y;
                size[y] += size[x];
                size[x] = 0;
                if (rank[x] == rank[y])
                {
                    rank[y]++;
                }
            }
        }
        public int FindSet(int x)
        {
            if (x != p[x])
            {
                p[x] = FindSet(p[x]);
            }
            return p[x];
        }
        public int Size(int x)
        {
            int root = FindSet(x);
            return size[root];
        }
    }
    public class PriorityQueue<T> where T : IComparable
    {
        private IComparer<T> _comparer = null;
        private int _type = 0;

        private T[] _heap;
        private int _sz = 0;

        private int _count = 0;

        /// <summary>
        /// Priority Queue with custom comparer
        /// </summary>
        public PriorityQueue(int maxSize, IComparer<T> comparer)
        {
            _heap = new T[maxSize];
            _comparer = comparer;
        }

        /// <summary>
        /// Priority queue
        /// </summary>
        /// <param name="maxSize">max size</param>
        /// <param name="type">0: asc, 1:desc</param>
        public PriorityQueue(int maxSize, int type = 0)
        {
            _heap = new T[maxSize];
            _type = type;
        }

        private int Compare(T x, T y)
        {
            if (_comparer != null) return _comparer.Compare(x, y);
            return _type == 0 ? x.CompareTo(y) : y.CompareTo(x);
        }

        public void Push(T x)
        {
            _count++;

            //node number
            var i = _sz++;

            while (i > 0)
            {
                //parent node number
                var p = (i - 1) / 2;

                if (Compare(_heap[p], x) <= 0) break;

                _heap[i] = _heap[p];
                i = p;
            }

            _heap[i] = x;
        }

        public T Pop()
        {
            _count--;

            T ret = _heap[0];
            T x = _heap[--_sz];

            int i = 0;
            while (i * 2 + 1 < _sz)
            {
                //children
                int a = i * 2 + 1;
                int b = i * 2 + 2;

                if (b < _sz && Compare(_heap[b], _heap[a]) < 0) a = b;

                if (Compare(_heap[a], x) >= 0) break;

                _heap[i] = _heap[a];
                i = a;
            }

            _heap[i] = x;

            return ret;
        }

        public int Count()
        {
            return _count;
        }

        public T Peek()
        {
            return _heap[0];
        }

        public bool Contains(T x)
        {
            for (int i = 0; i < _sz; i++) if (x.Equals(_heap[i])) return true;
            return false;
        }

        public void Clear()
        {
            while (this.Count() > 0) this.Pop();
        }

        public IEnumerator<T> GetEnumerator()
        {
            var ret = new List<T>();

            while (this.Count() > 0)
            {
                ret.Add(this.Pop());
            }

            foreach (var r in ret)
            {
                this.Push(r);
                yield return r;
            }
        }

        public T[] ToArray()
        {
            T[] array = new T[_sz];
            int i = 0;

            foreach (var r in this)
            {
                array[i++] = r;
            }

            return array;
        }
    }
}