トップページに戻る    次の競技プログラミングの問題へ    前の競技プログラミングの問題へ

AGC-019-B Reverse and Compare

■■■問題■■■

英小文字からなる文字列 A=A1A2 ・・・ An があります。

あなたは 1 <= i <= j <= n であるような任意の2つの添字 i,j を選び、
Aのうち部分文字列 AiAi+1 ・・・ Aj を反転することができます。

この操作は1回まで行うことができます。
これによって得られる文字列は何通りあるでしょうか?

■■■入力■■■

A

●1 <= |A| <= 20万
●Aは英小文字からなる

■■■出力■■■

Aのうち任意の部分文字列を1回まで反転することによって、
何通りの文字列が得られるか出力せよ。


C#のソース

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

class Program
{
    static string InputPattern = "Input1";

    static List<string> GetInputList()
    {
        var WillReturn = new List<string>();

        if (InputPattern == "Input1") {
            WillReturn.Add("aatt");
            //5
            //得られる文字列は
            //aatt(何もしない)、
            //atat(A[2..3] を反転)、
            //atta(A[2..4] を反転)、
            //ttaa(A[1..4] を反転)、
            //taat(A[1..3] を反転)です。
        }
        else if (InputPattern == "Input2") {
            WillReturn.Add("xxxxxxxxxx");
            //1
            //どの部分文字列を反転しても、結果はxxxxxxxxxxです
        }
        else if (InputPattern == "Input3") {
            WillReturn.Add("abracadabra");
            //44
        }
        else {
            string wkStr;
            while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
        }
        return WillReturn;
    }

    static void Main()
    {
        List<string> InputList = GetInputList();
        string A = InputList[0];

        long Answer = 1 + Derive_nC2(A.Length);
        foreach (var Each in A.ToCharArray().GroupBy(X => X)) {
            if (Each.Count() <= 1) continue;
            Answer -= Derive_nC2(Each.Count());
        }
        Console.WriteLine(Answer);
    }

    //nC2を返す
    static long Derive_nC2(long pN)
    {
        return pN * (pN - 1) / 2;
    }
}


解説

ABCという文字列で考えると、ABC,ACB,BAC,CAB の4通りだと分かります。
これは、1 + 3C2 です。

ABCDEFGHIJという文字列で考えると、
(1 + 10C2) 通りだと分かります。

AABBという文字列で考えると、
(1 + 4C2 - 2C2 - 2C2) 通りだと分かります。
元々の文字列の1通りと、
始点と終点 (始点 != 終点) を指定しての回文作成が 4C2 通りあり
同じ文字列同士で始点と終点となる場合が、Aで2C2通り、Bで2C2通りだからです。

引き算している理由ですが、
同じ文字列同士で始点と終点となる場合は、
内部に同じ文字列同士でない始点と終点を内包してたら、別途カウントしているので、
回文作成の場合の数から引く必要があるからです。

ABCBCAAABDという文字列で考えると、
(1 + 10C2 - 4C2 - 3C2 - 2C2) 通りだと分かります。
元々の文字列の1通りと、
始点と終点 (始点 != 終点) を指定しての回文作成が 10C2 通りあり
同じ文字列同士での始点と終点となる場合が、Aで4C2通り、Bで3C2通り、Cで2C2通りだからです。