[CF794G]すべてを置き換える【組み合わせ数学】【数論】

ねえ、私はソリューションを書かずにCFを持っていましたか?

考慮しないために?方法がに知られている場合を(C、D \)\された?合法的なを見つけるためにどのように文字の実施形態では、後に交換\(01 \)文字列のタプル\((S、T) \)数量。

セット\(A_X、b_x \)文字列を表す\(X \)にはAB数は、以下の2つのケースを考えてみます。

  1. \(a_c <a_d \)かつ\(b_c> b_d \)
  2. \(a_c> a_d \)かつ\(b_c <b_d \)
  3. \(a_c = a_d \)および\(b_c = b_d \)

お知らせ\(| \ GEQ 1 \ S |、| |トン)ので、3外の場合、それかどうかについて、\(|よ|、| T | \) 整理する方法、彼らは完全に置換することはできません(\ 01 \)シーケンスの長さが等しい。最初の2つのケースは実際には対称的であるため、ここでは最初のケースのみを考慮します。

置き換えられた\(01 \)シーケンス長さを等しくするために、\((a_d-a_c)| s | =(b_c-b_d)| t | \)を取得できますセット\(G = \ GCD(a_dある-A_C、B_c-B_D)\) 見つけることは困難ではない、\(| S | \)最小\(M_S = \ {B_c FRAC-B_D {G}} \) \(| t | \)\(m_t = \ frac {a_d-a_c} {g} \)の対応する最小値\ (m_t \ leq m_s \)を設定することもできます

ための\(\ GCD(M_S、M_t)= 1 \) 見つけることは困難ではない、任意の\(X \ [0、M_S)\) ユニーク有する[0、で\(Y \ \)M_S)を、\(y \ cdot m_t \ equiv x \ pmod {m_s} \)を作成します。言い換えれば、連続用(M_t \)\ \(S \)系列、私たちは何よりもの切片長に進み\(M_t \)を正確にダウンした断面の\(S \ )各サイクル(即ち、の\(S \)プレフィックスを降ろすために、無傷の受信\(S \)を)以下。この場合、\(s、t \)には2つのスキームしかないことを見つけるのは難しくありません。すべて\(0 \)で構成されているか、すべて\(1 \)で構成されています。このシーケンスを正の整数パスにコピーし、いくつかの\(s \)または\(t \)を特定の位置挿入した場合、これらの文字列がインターセプト中に個別にインターセプトされている限り、上記のプロパティが保持されることを見つけるのは難しくありません

上記の段落の最後の文、実際に満たすどのような状況のために、発現され(1 \)は\(の場合には(2 \)\類似)、決定\(A_C、a_d、b_c、 B_D \) \( C、D \)スケジューラの文字列は、我々は唯一の懸念している\(a_d-A_C \)(b_c-B_D \)\値が、これらを気にしないAB特定の場所を。そして、対応する\(s、t \)スキーム数を計算できます具体的には、まず最初に、\(| s |、| t | \)それぞれ\(m_s、m_t \)の倍数であり、\(| s | = k \ cdot m_s、| t | = k \ cdot m_t \)現時点では、\(2 ^ k \)スキームがあります(非素数部分は上記の方法では取得できないため、これらの位置は偶然に\(k \)の独立した接続された値のブロックに分割されます)。これは、比例シーケンスの単純な合計です。

したがって、\(a_d-a_c \)の値を激しく列挙することができます。見つけることは困難ではない?\(C、D \)の数が決定され、我々は直接計算することができます\(b_c-B_Dを\)の値。別の問題は、\((a_c、a_d、b_c、b_d)\)のグループが複数存在する可能性があることです。しかし、見つけることができる何の感情的な理解、保存しておきたい場合(a_d-A_C \)\(\ b_c-B_D)\を、各中、変わらない\(Cを\) 2つ以上がで?置き換えられA、それがなければならない(D \ \ )主に?置き換えますB換言すれば、\(A_C + B_D \)の値が決定され、この場合には、される?文字の数で置換のみを有するプログラムである\(A_C + B_D \)の組み合わせの数に関連する(実際にはあります(ヴァンダーモンドのアイデンティティ)。

今でも状況はあります\(3 \)\(3 \)の場合、\(| s |、| t | \)には制限がないことが判明したため、各\(の正当な\(\((s |、| t |)\)見つける必要がありますs、t \)数量。実際、上記の説明と同様に、\(\ gcd(| s |、| t |)= 1 \)の場合、\(s、t \)もすべて\(0 \)またはすべて\( 1 \)少し拡張すると、求めているのは\(\ sum_ {| s | = 1} ^ {n} \ sum_ {| t | = 1} ^ n 2 ^ {\ gcd(| s |、| t |)}であることがわかります\)これは非常に単純なので、ここでは繰り返しません。そして?別の実施形態は、文字の数は、実際には、上記と同様です。

ただし、最後のピットが1つあります。場合(C = D \)\、各位置は、そのどの手段A/Bは、長さのいずれかが超えない等しく(N- \)\ \((S、T)\ ) 明らか条件を満たしています。したがって、この部分は上記から差し引いて別に計算する必要があります。

コード:

#include <bits/stdc++.h>
#define R register
#define mp make_pair
#define ll long long
#define pii pair<int, int>
using namespace std;
const int mod = 1e9 + 7, N = 310000, M = N << 1;

int n, m, k, sa, sb, ta, tb, sc, tc, ispr[N], mu[N];
ll fac[M], inv[M];
char s[N], t[N];
vector<int> prime;

inline int addMod(int a, int b) {
	return (a += b) >= mod ? a - mod : a;
}

inline ll quickpow(ll base, ll pw) {
	ll ret = 1;
	while (pw) {
		if (pw & 1) ret = ret * base % mod;
		base = base * base % mod, pw >>= 1;
	}
	return ret;
}

template <class T>
inline void read(T &x) {
	x = 0;
	char ch = getchar(), w = 0;
	while (!isdigit(ch)) w = (ch == '-'), ch = getchar();
	while (isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
	x = w ? -x : x;
	return;
}

inline void initComb(int n) {
	fac[0] = 1;
	for (R int i = 1; i <= n; ++i) fac[i] = fac[i - 1] * i % mod;
	inv[n] = quickpow(fac[n], mod - 2);
	for (R int i = n; i; --i) inv[i - 1] = inv[i] * i % mod;
}

inline ll comb(int n, int m) {
	if (m < 0 || n < m) return 0;
	return fac[n] * inv[m] % mod * inv[n - m] % mod;
}

int getGcd(int a, int b) {
	return b ? getGcd(b, a % b) : a;
}

inline ll calc(int x) {
	return addMod(quickpow(2, x + 1), mod - 2);
}

inline int sign(int x) {
	return x < 0 ? -1 : x > 0;
}

void initPrime(int n) {
	mu[1] = 1;
	for (R int i = 2, k; i <= n; ++i) {
		if (!ispr[i])
			mu[i] = -1, prime.push_back(i);
		for (auto &j : prime) {
			if ((k = i * j) > n) break;
			ispr[k] = 1;
			if (i % j == 0) break;
			mu[k] = addMod(mod, -mu[i]);
		}
	}
	return;
}

inline ll sq(ll x) {
	return x * x % mod;
}

int main() {
	scanf("%s%s", s + 1, t + 1), read(k);
	n = strlen(s + 1), m = strlen(t + 1);
	if (n < m) swap(s, t), swap(n, m);
	initComb(n + m), initPrime(k);
	for (R int i = 1; i <= n; ++i)
		sa += s[i] == 'A', sb += s[i] == 'B', sc += s[i] == '?';
	for (R int i = 1; i <= m; ++i)
		ta += t[i] == 'A', tb += t[i] == 'B', tc += t[i] == '?';
	ll ans = 0;
	for (R int i = sa - ta - tc; i <= sa - ta + sc; ++i) {
		int j = m - n + i;
		if (i == 0 && j == 0) {
			ll w = 0, pw = 1;
			for (R int d = 1; d <= k; ++d) {
				pw = addMod(pw, pw);
				for (R int u = 1, v = d; v <= k; ++u, v += d)
					w = (w + pw * mu[u] % mod * sq(k / v)) % mod;
			}
			pw = 1;
			for (R int d = 1; pw && d <= n; ++d) {
				if (s[d] == '?' && t[d] == '?')
					pw = addMod(pw, pw);
				else if (s[d] != '?' && t[d] != '?' && s[d] != t[d])
					pw = 0;
			}
			ans = (ans + w * (comb(sc + tc, ta + tc - sa + i) + mod - pw)) % mod;
			ans = (ans + pw * sq(calc(k))) % mod;
		}
		if (sign(i) * sign(j) != 1) continue;
		ans = (ans + calc(k / ((i < 0 ? j : i) / getGcd(i, j))) * comb(sc + tc, ta + tc - sa + i)) % mod;
	}
	cout << ans << endl;
	return 0;
}

おすすめ

転載: www.cnblogs.com/suwakow/p/12748947.html