← 全部文章

AtCoder Grand Contest 047 题解

本文目录(6 节)
  1. Integer Product
  2. First Second
  3. Product Modulo
  4. Twin Binary Trees
  5. Product Simulation
  6. Rooks

AtCoder Grand Contest 047

Integer Product

考虑 ×109\times 10^9 之后质因子中 2,52,5 的次数,卡精度。

const int M = 57, inf = 1e9;
int n, c[M][M];
ll ans;

int main() {
	ios::sync_with_stdio(0);
	rd(n);
	for (int i = 1; i <= n; i++) {
		string s;
		rds(s);
		int p = -1;
		for (ui j = 0; j < s.size(); j++)
			if (s[j] == '.') p = j;
		if (!~p) p = s.size(), s += ".0";
		while ((int)s.size() - p < 10) s += "0";
		ll a = 0;
		for (ui j = 0; j < s.size(); j++)
			if (s[j] != '.') a = a * 10 + s[j] - '0';
		int c2 = 0, c5 = 0;
		while (a % 2 == 0) ++c2, a /= 2;
		while (a % 5 == 0) ++c5, a /= 5;
		c[c2][c5]++;
	}
	for (int i = 0; i < M; i++)
		for (int j = 0; j < M; j++) {
			if (i >= 9 && j >= 9) ans += 1ll * c[i][j] * (c[i][j] - 1);
			for (int x = 0; x < M; x++)
				for (int y = 0; y < M; y++)
					if (i + x >= 18 && j + y >= 18 && (i != x || j != y))
						ans += 1ll * c[i][j] * c[x][y];
		}
	print(ans / 2);
	return 0;
}

First Second

所有字符串能生成的新字符串只有 O(∣Σ∣∑i=1n∣si∣)\mathcal O(|\Sigma|\sum_{i=1}^n |s_i|),Hash 判即可。

const int P[2] = {998244353, 998244853}, H = 19491001;
struct Hash {
	int a[2];
	inline Hash() {}
	inline Hash(int x) {
		a[0] = a[1] = x;
	}
	inline Hash(int x, int y) {
		a[0] = x, a[1] = y;
	}
	inline friend bool operator == (Hash x, Hash y) {
		for (int i = 0; i < 2; i++)
			if (x.a[i] != y.a[i]) return 0;
		return 1;
	}
	inline friend Hash operator + (Hash x, Hash y) {
		for (int i = 0; i < 2; i++)
			x.a[i] = (x.a[i] + y.a[i]) % P[i];
		return x;
	}
	inline friend Hash operator - (Hash x, Hash y) {
		for (int i = 0; i < 2; i++)
			x.a[i] = (x.a[i] - y.a[i] + P[i]) % P[i];
		return x;
	}
	inline friend Hash operator * (Hash x, Hash y) {
		for (int i = 0; i < 2; i++)
			x.a[i] = 1ll * x.a[i] * y.a[i] % P[i];
		return x;
	}
	inline ll h() {
		return ((ll)1e9 * a[1] + a[0]) % H;
	}
};

const Hash B = Hash(131, 13331);

const int N = 2e5 + 7;
int n, m;
string s[N];
vector<Hash> h[N];

int hh[H], he[N], hc[N], ht[N], tot;

inline void add(int x, int y, int z) {
	for (int i = hh[x]; i; i = ht[i])
		if (he[i] == y) return hc[i] += z, void();
	he[++tot] = y, hc[tot] = z, ht[tot] = hh[x], hh[x] = tot;
}

inline int ask(int x, int y) {
	for (int i = hh[x]; i; i = ht[i])
		if (he[i] == y) return hc[i];
	return 0;
}

ll ans;

int main() {
	rd(n);
	for (int i = 1; i <= n; i++) {
		rds(s[i]), reverse(s[i].begin(), s[i].end());
		h[i].resize(s[i].size());
		h[i][0] = s[i][0];
		for (ui j = 1; j < s[i].size(); j++)
			h[i][j] = h[i][j-1] * B + s[i][j];
		add(h[i][s[i].size()-1].h(), h[i][s[i].size()-1].a[0], 1);
	}
	for (int i = 1; i <= n; i++) {
		static bool v[26];
		memset(v, 0, sizeof(v));
		for (int j = s[i].size() - 1; ~j; j--) {
			v[s[i][j]-'a'] = 1;
			if (j != (int)s[i].size() - 1) {
				Hash o = j ? h[i][j-1] : 0;
				for (int k = 0; k < 26; k++)
					if (v[k]) {
						Hash w = o * B + (k + 'a');
						ans += ask(w.h(), w.a[0]);
					}
			}
		}
	}
	print(ans);
	return 0;
}

Product Modulo

考虑找到 PP 的一个原根 pp,将除了 00 之外的每个数转化成 2k mod P2^k \bmod P 的形式,那么乘法取模就相当于指数上的循环卷积,FFT 实现,时间复杂度 O(Plog⁡P)\mathcal O(P \log P)。

取 p=2p=2 即可。

const int P = 2e5 + 3;
int n, c[P], p[P];
ll d[P], ans;

namespace FFT {
	const int N = 1 << 21 | 1;
	const ld PI = acos(-1);
	struct I {
		ld x, y;
		inline I() {}
		inline I(ld x, ld y) : x(x), y(y) {}
		inline I &operator = (int o) { return x = o, y = 0, *this; }
		inline I operator + (const I o) const { return I(x + o.x, y + o.y); }
		inline I operator - (const I o) const { return I(x - o.x, y - o.y); }
		inline I operator * (const I o) const {
			return I(x * o.x - y * o.y, x * o.y + y * o.x);
		}
	} a[N], b[N];
	int n, m, k, l, r[N];
	inline void fft(I *a, int n, int x) {
		for (int i = 0; i < n; i++) if (i < r[i]) swap(a[i], a[r[i]]);
		for (int o = 2, k = 1; o <= n; o <<= 1, k <<= 1) {
			I W = I(cos(PI / k), x * sin(PI / k));
			for (int i = 0; i < n; i += o) {
				I w = I(1, 0);
				for (int j = 0; j < k; j++, w = w * W) {
					I x = a[i+j], y = w * a[i+j+k];
					a[i+j] = x + y, a[i+j+k] = x - y;
				}
			}
		}
	}
	inline void solve() {
		k = 1, l = 0;
		while (k <= n + m) k <<= 1, ++l;
		for (int i = 0; i < k; i++)
			r[i] = (r[i>>1] >> 1) | ((i & 1) << (l - 1));
		for (int i = n + 1; i < k; i++) a[i] = 0;
		for (int i = m + 1; i < k; i++) b[i] = 0;
		fft(a, k, 1), fft(b, k, 1);
		for (int i = 0; i < k; i++) a[i] = a[i] * b[i];
		fft(a, k, -1);
		for (int i = 0; i <= n + m; i++) a[i].x /= k;
	}
}

int main() {
	rd(n);
	for (int i = 1, x; i <= n; i++) {
		rd(x);
		if (x) ++c[x];
	}
	FFT::n = FFT::m = P - 2;
	for (int i = 0; i <= P - 2; i++) {
		p[i] = i ? 2 * p[i-1] % P : 1;
		FFT::a[i] = FFT::b[i] = c[p[i]];
		d[2*i%(P-1)] -= c[p[i]];
	}
	FFT::solve();
	for (int i = 0; i <= 2 * P - 4; i++)
		d[i%(P-1)] += (ll)(FFT::a[i].x + 0.5);
	for (int i = 0; i <= P - 2; i++) ans += d[i] * p[i];
	print(ans / 2);
	return 0;
}

Twin Binary Trees

设第一棵树上的两个叶子为 u,vu,v,其 LCA 为 ww。

枚举 ww。

枚举 uu,设其对应的第二棵树上的叶子为 pup_u,枚举 pup_u 的祖先 xx,将 w→xw \to x 的贡献加到 xx 上。

枚举 vv,设其对应的第二棵树上的叶子为 pvp_v,枚举 pvp_v 的祖先 yy,计算 pu,pvp_u,p_v 的 LCA 为 yy 时的贡献。

时间复杂度 O(nlog⁡2n)\mathcal O(n \log^2 n)。

const int N = 1 << 18 | 1;
int n, l, r, a[N];
modint f[N], ans;

void dfs1(int p, modint w) {
	w *= p;
	if (p >= l) {
		p = a[p];
		while (p) w *= p, f[p] += w, p >>= 1;
		return;
	}
	dfs1(ls, w), dfs1(rs, w);
}

void dfs2(int p, modint w) {
	w *= p;
	if (p >= l) {
		p = a[p];
		while (p != 1) w *= p, ans += w * f[p^1] * (p >> 1), p >>= 1;
		return;
	}
	dfs2(ls, w), dfs2(rs, w);
}

void dfs3(int p) {
	if (p >= l) {
		p = a[p];
		while (p) f[p] = 0, p >>= 1;
		return;
	}
	dfs3(ls), dfs3(rs);
}

int main() {
	rd(n), l = 1 << (n - 1), r = 1 << n;
	for (int i = l; i < r; i++) rd(a[i]), a[i] += l - 1;
	for (int p = 1; p < l; p++) dfs1(ls, p), dfs2(rs, 1), dfs3(ls);
	print(ans);
	return 0;
}

Product Simulation

先把 A,BA,B 的二进制数搞出来,然后一位一位的乘再加起来即可,具体构造方式见代码。

#define p(x, a, b, c) printc(x), printc(' '), print(a, b, c)

int main() {
	print(3870);
	p('+', 0, 1, 3);
	p('<', 2, 3, 3);
	for (int x = 0; x < 2; x++) {
		p('+', 3, x, x);
		int y = x + 4;
		for (int i = 0; i < 30; i++) {
			if (i > 0) p('+', y, y, y);
			p('+', y, 3, 6);
			for (int j = i; j < 29; j++) p('+', 6, 6, 6);
			int z = i + 7 + x * 30;
			p('<', 6, x, z);
			p('+', y, z, y);
		}
	}
	for (int t = 0; t < 59; t++) {
		if (t > 0) p('+', 2, 2, 2);
		for (int i = max(t - 29, 0); i <= min(t, 29); i++) {
			int j = t - i;
			p('+', i + 7, j + 37, 4);
			p('<', 3, 4, 4);
			p('+', 2, 4, 2);
		}
	}
	return 0;
}

Rooks

咕。

标签:FFT、Hash、数论、构造、组合计数

评论

    填写昵称即可留言。评论经站主审核后公开,请勿提交私人信息。

    正在连接评论服务…