TopCoder SRM 603 Div1 Medium PairsOfStrings
問題
n文字でアルファベットの最初のk種類からなる文字列A, Bのうち、
次の条件を満たす(A, B)のペアの総数をmod 10^9 + 7で求めよ。
ある文字列Cが存在し、A + C = C + Bとなる。
(ただし + は文字列の結合を表す)
AまたはBが一文字でも違うとき、二つのペアは異なると数えるものとする。
制約条件
n≦10億
k≦26
方針
A + C = C + Bになるということは、
Bの先頭何文字かを切り取ってBの末尾につけると、Aに一致するということ。
文字列Aの末尾を切り取ってBを何通り生成できるかを、重複なく数えられればよい。
一つのAに対して、違う位置で切り取って、同じBが生成されてしまう必要十分条件を考えると、
文字列Aの周期がTであるときに、n/T回同じ切断で同じ文字列が生成されることがわかる。
周期がTの文字列をそれぞれ何通りあるか包除原理で数え、
切断箇所T通り倍するのを、それぞれのTについて足し合わせればいい。
ソースコード
const int mod = (int)1e9 + 7; ll pw(ll n, ll m){ ll res = 1; for(; m; m /= 2){ if(m & 1) res = res * n % mod; n = n * n % mod; } return res; } map<int, int> dp; int calc(int n, int k){ if(dp.count(n)) return dp[n]; ll res = (pw(k, n) + mod - dp[1]) % mod; for(int i = 2; i * i <= n; i++) if(n % i == 0){ res = (res + mod - calc(i, k)) % mod; if(i * i != n) res = (res + mod - calc(n / i, k)) % mod; } return dp[n] = res; } class PairsOfStrings { public: int getNumber(int n, int k) { dp.clear(); dp[1] = k; calc(n, k); ll ans = 0; each(i, dp){ ans += (ll)i->first * i->second % mod; } return ans % mod; } };