読者です 読者をやめる 読者になる 読者になる

Lilliput Steps

小さな一歩から着実に. 数学やプログラミングのことを書きます.

Codeforces 356B - Xenia and Hamming

問題 : Xenia and Hamming

概要 :

文字列$x$ を$n$ 回繰り返した文字列$a$ と, 文字列$y$ を$m $ 回繰り返した文字列$b$ がある.

$a$ と$b$ のハミング距離を求めよ. ただし, ハミング距離とは$\displaystyle \sum_{i=1}^{n} [a_i \neq b_i]$ で定義され, $a_i = b_i$ なら$[a_i \neq b_i] = 0$, $a_i \neq b_i$ なら$[a_i \neq b_i] = 1$ とする.

$1 \leqq n,\ m \leqq 10^{12}$
$1 \leqq |x|,\ |y| \leqq 10^6$
$n|x| = m|y|$
文字列は英小文字からのみ成る.

解法 :

それぞれの文字列は$\gcd(|x|,\ |y|)$ ごとにグループに分かれ, それぞれのグループの間の文字の組み合わせはすべて掛け合わされる. よって, $\gcd(|x|, \ |y|)$ ごとに文字の出現頻度を数えて, 幾つの文字が等しくなるかを調べて全体から引けば良い.

コード :

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long lint;

lint gcd(lint x, lint y)
{
	if (x < y) swap(x, y);
	return (!y ? x : gcd(y, x % y));
}

lint lcm(lint x, lint y)
{
	return (x / gcd(x, y) * y);
}

int ctx[1000001][26], cty[1000001][26];

int main()
{
	lint m, n, lx, ly;
	static char x[1000001], y[1000001];
	
	scanf("%lld %lld", &m, &n);
	scanf("%s", x);
	scanf("%s", y);
	
	lx = strlen(x); ly = strlen(y);
	lint g = gcd(lx, ly);
	
	for (int i = 0; x[i]; i++) ctx[i % g][x[i] - 'a']++;
	for (int i = 0; y[i]; i++) cty[i % g][y[i] - 'a']++;
	
	lint same = 0;
	
	for (int i = 0; i < g; i++){
		for (int j = 0; j < 26; j++){
			same += (lint)ctx[i][j] * cty[i][j];
		}
	}
	
	same = same * (lx * m / lcm(lx, ly));
	
	lint ans = lx * m - same;
	
	printf("%lld\n", ans);
	
	return (0);
}