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('
');
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
", ans);
return 0;
}
C. 基因##
据说考点是 AC 自动机和 DP , 以及矩阵乘法(蒟蒻乘法)。