1014 CW 模拟赛 D.进化
题面
挂个 pdf
题面下载
算法
分析题目发现, 一次进化等效于:
在 \(a\) 两端加 \(0\)
对于 \(i \in [1, n], a_i \leftarrow a_{i - 1} \oplus a_{i + 1}\)
于是猜测在 \(k\) 次操作之后
有 \(a_i \leftarrow a_{i + k} \oplus a_{i - k}\)
代入计算后发现这个式子显然错误, 原因是当 \(k\) 足够大时, \(a\) 显然会变成全 \(0\), 但这不符合题意
考虑构造一个环, 这样在进化时就不会超出范围
对于\(i = 0\), 其左侧需要一个 \(a_{i + 1}\), 对于其左侧, 需要一个 \(a_{i + 2}\), 最后会变成一个环 \(c\)

以下 \(l_i\) 表示向左移动 \(i\), \(r_i\) 表示向右移动 \(i\)
观察 \(T = 1\)
此时答案为 \(l_1 \oplus r_1\)
观察 \(T = 2\)
此时答案为 \((l_2 \oplus c) \oplus (c \oplus r_2) = l_2 \oplus r_2\)
观察 \(T = 3\)
发现消不掉
观察 \(T = 4\)
发现为 \(l_4 \oplus r_4\)
所以对于 \(T = 2^d\), 答案为 \(l_{2^d} \oplus r_{2^d}\)
对于其他 \(T\), 二进制拆分之后将答案异或即可, 时间复杂度 \(O(n \log T)\)
代码
#include <bits/stdc++.h>
#define int long long
const int MAXN = 1e5 + 20;
int T;
int n;
std::string a_str;
int a[MAXN];
int c[MAXN << 2];
int c_copy[MAXN << 2];
signed main()
{
scanf("%lld", &T);
/*读入 + 建环*/
scanf("%lld", &n);
std::cin >> a_str;
for (int i = 1; i <= n; i++)
{
a[i] = a_str[i - 1] - '0';
}
c[0] = c[n + 1] = 0;
for (int i = 1; i <= n; i++)
{
c[i] = c[2 * n + 2 - i] = a[i];
}
int Now_d = 1;
while(T)
{
if(T & 1)
{
for (int i = 0; i <= 2 * n + 1; i++)
{
c_copy[i] = c[i];
}
for (int i = 0; i <= 2 * n + 1; i++)
{
c[i] = c_copy[((i - Now_d) % (2 * n + 2) + (2 * n + 2)) % (2 * n + 2)] ^ c_copy[((i + Now_d) % (2 * n + 2) + (2 * n + 2)) % (2 * n + 2)];
}
}
Now_d <<= 1;
T >>= 1;
}
for (int i = 1; i <= n; i++)
{
printf("%lld", c[i]);
}
return 0;
}
/*
2 5
00100
10001
*/
总结
变换类题目, 一般要构造循环节 / 环状结构
对于一些式子, 若没有较好的通项公式, 考虑枚举之后找规律
注意开 long long
用数组模拟环状结构善于利用 \(\rm{mod}\) 运算
-
左边(设当前位置为 \(i\), 左移位置为 \(d\))
\(a_{(((i - d) \text{ } \rm{ mod } \text{ } Len) + Len) \text{ } \rm{ mod } \text{ } Len}\)
防爆炸 -
右边(设当前位置为 \(i\), 右移位置为 \(d\))
\(a_{(((i + d) \text{ } \rm{ mod } \text{ } Len) + Len) \text{ } \rm{ mod } \text{ } Len}\)
防爆炸

浙公网安备 33010602011771号