比赛-sparrow学长的训练赛 (21 Aug, 2018)

A. ‘+’ 和 ‘√’##

考虑第 \(k\) 轮时应把数字 \(x_k\) 增加到 \(t_k\) ,使得 \(\sqrt{t_k}\) 是 \(k + 1\) 倍数,同时 \(t_k\) 本身是 \(k\) 的倍数。即 \(t_k = f \cdot (k + 1)^2 \cdot k\) , \(f\) 是整数。由于 \(t_k\) 也是一个完全平方数,所以考虑直接让 \(f = k\) ,则 \(t_k = ((k + 1) \cdot k)^2\) 。这样在 \(n = 100000\) 时,最大的答案似乎是 \(16\) 位的,没有爆掉,就很好,水过去了。

#include <cstdio>
#include <ctype.h>
#include <stack>

using namespace std;

typedef long long ll;

char buf[1<<20], *p1, *p2;
#define GC (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?0:*p1++)

template<typename T>
void rd(T &num)
{
	char tt;
	while (!isdigit(tt = GC));
	num = tt - '0';
	while (isdigit(tt = GC))
		num = num * 10 + tt - '0';
	return;
}

template<typename T>
void pt(T num)
{
	stack<char> SSS;
	do SSS.push(num % 10 + '0');
	while (num /= 10);
	while (!SSS.empty())
		putchar(SSS.top()), SSS.pop();
	putchar('\n');
	return;
}

ll N;

int main()
{
	rd(N);
	ll X = 2, K = 1;
	for (int i = 1; i <= N; ++i) {
		pt(K * (K + 1) * (K + 1) - X / K);
		X = K * (K + 1);
		++K;
	}
	return 0;
}

B. DFS 序##

考虑在节点 \(p\) 时,向没有遍历过的节点继续搜索。下一步可以是若干节点中的任意一个,因此可以用 next_permutation() 枚举一下遍历顺序。这样可以拿到暴力分 20 。正解是 DP 和记忆化搜索。 状态 \(f_{p, S}\) 表示在讨论完 \(S\) 集合的节点,当前在 \(p\) 号节点时,继续遍历整张图的总方案数。枚举 \(p\) 关联的不在 \(S\) 集合的点 \(i\) 。如果接下来向 \(i\) 遍历,再次回溯到 \(p\) 时,显然已经遍历完了 \(i\) 所在的与 \(S\) 没有交集的那部分强联通分量 \(T\) 。因此之后的遍历是以 \(S \cup T\) 为新的 \(S'\) , \(p\) 为新的 \(p'\) 进行的。选择向 \(i\) 遍历这一方案,和遍历完之后回溯到 \(p\) 再向其他节点遍历这一方案,互不影响。根据乘法原理:

\[f(p,S) = \sum f(p, S \cup T) \cdot f(i, S \cup i) \]

求 \(T\) 可以提前预处理,也可以在搜索中暴力 BFS 或者 DFS 。

#include <stdio.h>
#include <queue>
#include <string.h>

using namespace std;

typedef long long ll;

ll ans, f[1 << 14][15];
int N;
char str[20];
bool G[20][20];

ll dfs(int s, int p)
{
	if (~f[s][p]) return f[s][p];
	f[s][p] = 0;
	for (int i = 1; i <= N; ++i) {
		if (G[p][i] && ((s >> (i - 1)) & 1 ^ 1)) {
			int t = 1 << (i - 1);
			queue<int> Q;
			Q.push(i);
			while (!Q.empty()) {
				int tmp = Q.front();
				Q.pop();
				for (int g = 1; g <= N; ++g)
					if (G[tmp][g] && ((s >> (g - 1)) & 1 ^ 1) && ((t >> (g - 1)) & 1 ^ 1)) {
						t |= 1 << (g - 1), Q.push(g);
					}
			}
			f[s][p] += dfs(s | t, p) * dfs(s | (1 << (i - 1)), i);
		}
	}
	f[s][p] = max(f[s][p], 1ll);
	return f[s][p];
}

int main()
{
	scanf("%d", &N);
	for (int i = 1; i <= N; ++i) {
		scanf("%s", str + 1);
		for (int j = 1; j <= N; ++j)
			G[i][j] = str[j] == 'Y';
	}
	memset(f, -1, sizeof f);
	for (int i = 1; i <= N; ++i)
		ans += dfs(1 << (i - 1), i);
	printf("%lld\n", ans);
	return 0;
}

C. 基因##

据说考点是 AC 自动机和 DP , 以及矩阵乘法(蒟蒻乘法)。

posted @ 2018-08-21 18:30  derchg  阅读(124)  评论(0)    收藏  举报