0%

题目大意

题目总结:D. Doorway

说白了就是告诉你滑动门两边的墙壁,告诉你从左到右的滑动门的这个长度。然后有好几层的这样子的子的滑动门系统问你这样子的系统能够张开的最大口子长度是多少。

问题描述

在一个多层滑动门系统中,共有 nn 层。每一层可以看作一个水平区间,由左侧墙壁 xi,1x_{i,1} 和右侧墙壁 xi,2x_{i,2} 限定。每一层包含若干扇固定长度的滑动门,门可以在该层的墙壁范围内自由左右滑动,但不能相互重叠,也不能越过墙壁。

目标

寻找一个最大的开口(Opening)。开口定义为一个水平区间,使得在所有层中,该区间内的任何位置都没有任何门或墙壁遮挡。你需要通过调整每一层门的位置,使得这个公共开口的长度最大化。


输入格式

  • 第一行:层数 nn (1n1051 \le n \le 10^5)。

  • 接下来的 nn 行,每行描述一层:

    • 三个整数:门数量 kik_i、左墙坐标 xi,1x_{i,1}、右墙坐标 xi,2x_{i,2} (0xi,1<xi,21090 \le x_{i,1} < x_{i,2} \le 10^9)。
    • kik_i 个整数:该层从左到右每扇门的长度 li,jl_{i,j}
  • 数据保证 ki3105\sum k_i \le 3 \cdot 10^5

输出格式

  • 一个整数,表示通过移动门所能达到的最大公共开口长度。

样例解释

样例 1

  • 输入:

    • 第 1 层:墙在 [2,11][2, 11],门长 3 和 2。
    • 第 2 层:墙在 [4,12][4, 12],门长 1, 1 和 2。
  • 逻辑:
    所有层的共同墙壁限制区间为 [max(xi,1),min(xi,2)][\max(x_{i,1}), \min(x_{i,2})],即 [4,11][4, 11],长度为 7。

    • 在第 1 层中,如果将长为 3 的门推到最左,长为 2 的门推到最右,中间会留出空隙。
    • 在第 2 层中,通过合理分配门的位置,可以使得在 [4,11][4, 11] 这个范围内,所有层共同暴露出的最大空白区间长度为 4

样例 2

  • 输入:

    • 第 1 层:墙在 [0,7][0, 7],门长 2 和 4(总长 6,空隙 1)。
    • 第 2 层:墙在 [4,9][4, 9],门长 4(总长 4,空隙 1)。
  • 逻辑:
    第一层有效范围 [0,7][0, 7],第二层有效范围 [4,9][4, 9],它们的交集是 [4,7][4, 7],长度仅为 3。由于两层中都存在长度大于或等于交集长度的门或门组限制,无法在所有层中腾出一个完全没有遮挡的公共区间。

  • 输出: 0

注意

这个示例展示了第一个例子的解决方案。墙壁填充黑色,门填充各种灰色,开口是白色。当每层的第一个门向左移动,其余的门向右移动时,我们得到了最大的开口为4。

image

思路讲解

还是一样的思路啊,就是当你发现你只知道起始位置的时候,你会发现计算这个东西啊,其实不是很容易。

当然,我们上面所指的起始位置,其实是指的总体的起始位置。考虑到,虽然说总体的起始位置,知道总体的起始位置,然后我们去进行一个这个操作,它其实也是需要 O(N)O(N) 吧。

那我们曾经提及过非常多次,当我们发现采用总体的想法碰壁的时候,我们应该怎么样?我们应该采用更加细颗粒度的东西,是不是?因此我们可以采用每一个起始位置,就是每一个滑窗系统的起始位置,去解决以及考虑这个问题。

2025 United Kingdom and Ireland Programming Contest (UKIEPC 2025) 2025 英国 ICPC——B. Brickwork(判断砖块是否重叠)(扫描线的本质就是遍历一个出一个)(维护一个当前生效的集合)
为什么这道题目你需要去塞一个负无穷呢?是这样子的,这个是因为啊,我们另外一道题目就是这个 brick work 是处理这个不相交问题,但这道题目我们处理的是相交问题。不相交问题你自然是还没有启用的区间,你自然是不用往里面去塞的。但是集合相交问题,还没有启用的集合,需要往里塞一个未启用值,就是未生效值。因为它都没启用,它肯定是不相交的对吧,为了避免这种情况影响我们的最终判断,我们需要往里面塞一个未启用值?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
multiset<ll> ri_st;
// vector<Event> event_ls;
vector<ll> i_ri_ls(N + 2);
map<ll, vector<Event> > x1_idx_x2_mtx;
for (int i = 1; i <= N; ++i) {
ll sum = accumulate(all(door_mtx[i]), 0ll);
auto [x1,x2] = wall_pos[i];
x2 -= sum;
// 在没有碰到自己的左端点之前,这个滑动系统不应该贡献任何的这个有效的右端点。
ri_st.insert(-INF);
i_ri_ls[i] = -INF;
x1_idx_x2_mtx[x1].push_back({i, x2});
for (auto v: door_mtx[i]) {
x1 += v;
x2 += v;
x1_idx_x2_mtx[x1].push_back({i, x2});
}
}
ll ans = 0;
for (auto &[x1,vec]: x1_idx_x2_mtx) {
for (auto &[id,x2]: vec) {
ri_st.erase(ri_st.find(i_ri_ls[id]));
ri_st.insert(x2);
i_ri_ls[id] = x2;
}
ans = max(ans, *ri_st.begin() - x1);
}

AC代码

AC
https://codeforces.com/contest/2181/submission/362349671

心路历程(WA,TLE,MLE……)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
for (int i = 1; i <= N; ++i) {
ll sum = accumulate(all(door_mtx[i]), 0ll);
auto [x1,x2] = wall_pos[i];
x2 -= sum;
// 在没有碰到自己的左端点之前,这个滑动系统不应该贡献任何的这个有效的右端点。
ri_st.insert(-INF);
i_ri_ls[i] = -INF;
x1_idx_x2_mtx[x1].push_back({i, x2});
for (auto v: door_mtx[i]) {
x1 += v;
x2 += v;
x1_idx_x2_mtx[x1].push_back({i, x2});
}
}

题目大意

经典的Nim游戏规则如下。有nn堆石头,第ii堆最初包含aia_i个石头。Alice和Bob轮流进行; Alice先行动。在他们的轮次中,玩家选择任意非空堆并从中移除任意正数个石头。拿到最后一块石头的玩家获胜。

在玩了很多Nim游戏之后,Alice和Bob决定稍微改变规则。在这一变体中,轮到的玩家不选择堆 — — 他们的对手为他们选择!然而,玩家仍然可以决定从那堆中移除多少石头。

Alice仍然先手。在Alice的轮次中,Bob选择任意非空堆,然后Alice从中移除任意正数个石头。同样地,在Bob的轮次中,Alice选择任意非空堆,然后Bob从中移除任意正数个石头。

对于给定的石头堆配置,确定如果两名玩家都遵循最佳策略,谁将获胜。

思路讲解

这种题目是这样子的,先碰到弹性堆的那一方,一定赢了。先碰到弹性堆的那一方一定赢了,这个是因为你不仅可以制造陷阱,还可以逼迫对手进入陷阱,这个是最厉害的地方。

  1. 全是 1 的情况bigs=0bigs = 0):每回合只能取 1 颗,总共 nn 回合,奇数轮 Alice 赢,偶数轮 Bob 赢——即 nn 为奇则 Alice 胜。

  2. 存在 >1>1 的堆时bigs1bigs \geq 1):当一个玩家被指向一个大堆(ai>1a_i > 1),他可以选择"全取"(消灭堆)或"留 1"(变成 size-1 堆)。这意味着他能自由控制对手下一步面对的 onesones 的奇偶性——因此被指向大堆的人必赢
    既然指向大堆 = 给对方胜利,所以"选堆方"(chooser)一定会优先把对手指向 size=1 的堆。双方轮流消耗 size-1 堆,直到 size-1 堆耗尽,最终被迫指向大堆的那一方就输了。
    消耗 onesones 个 size-1 堆需要 onesones 轮。若 onesones 为偶数,Alice 仍是 mover,获得大堆 → Alice 赢;若 onesones 为奇数,Bob 是 mover → Bob 赢

在变体 Nim 的纯弹性子游戏里,当前玩家必胜,本质上靠的是一个两步连招

第一步(你是操作者):对手把你指到某个弹性堆,你把它削成 1。你制造了一个"陷阱"。

第二步(你变成了选堆方):下一回合,角色互换——你来选堆,对手来操作。你把对手指向那个你刚造出来的大小为 1 的堆。对手被迫吃掉它,白白浪费一个回合。

净效果:两个回合过去了,一个弹性堆被消灭,又轮到你了。你从 ff 个弹性堆的先手,变成了 f1f-1 个弹性堆的先手。循环往复,直到只剩最后一个弹性堆,你直接清空获胜。

这个连招之所以成立,是因为操作者和选堆方的角色每回合交替。你当操作者时布下陷阱,下一回合你当选堆方时把对手推进陷阱。

AC代码

AC
https://codeforces.com/contest/2181/submission/362136313

心路历程(WA,TLE,MLE……)

题目大意

题目总结:M. Medical Parity

问题描述

给定两个长度为 nn 的二进制字符串 xx'(测试结果串)和 yy'(奇偶校验控制串)。

在理想情况下,字符串 yyxx 必须满足以下关系:

对于每一个位置 ii1in1 \le i \le n),yiy_i 是字符串 xxii 个字符中 ‘1’ 的数量对 2 取模的结果。

即:yi=(j=1ixj)(mod2)y_i = (\sum_{j=1}^{i} x_j) \pmod 2

这意味着:

  • 如果 xx 的前 ii 个字符中有奇数个 ‘1’,则 yi=1y_i = 1

  • 如果 xx 的前 ii 个字符中有偶数个 ‘1’,则 yi=0y_i = 0.

由于记录数据时可能存在错误,输入的 xx'yy' 可能不满足上述规则。你需要通过翻转最少数量的位(将 ‘0’ 变 ‘1’ 或将 ‘1’ 变 ‘0’),使得修改后的 yy 成为修改后的 xx 的合法奇偶校验控制串。翻转操作可以在 xx'yy' 的任意位置进行。

输出要求

输出使 yy 成为 xx 的合法奇偶校验串所需的最少总翻转次数。


样例解释

  • 样例 1
    输入:x=11101,y=10110x'=11101, y'=10110
    根据 xx' 计算合法的校验串 yy

    • i=1i=1: xx 前 1 位有 1 个 ‘1’(奇数),y1=1y_1=1
    • i=2i=2: xx 前 2 位有 2 个 ‘1’(偶数),y2=0y_2=0
    • i=3i=3: xx 前 3 位有 3 个 ‘1’(奇数),y3=1y_3=1
    • i=4i=4: xx 前 4 位有 3 个 ‘1’(奇数),y4=1y_4=1
    • i=5i=5: xx 前 5 位有 4 个 ‘1’(偶数),y5=0y_5=0
      计算得 y=10110y=10110,与给定的 yy' 完全一致。
      结论: 翻转次数为 0。
  • 样例 2
    输入:x=11101,y=10010x'=11101, y'=10010
    根据 xx' 计算出的合法 yy 应为 1011010110(见样例 1)。
    对比给定的 y=10010y'=10010,只有第 3 位不同(y3y_3 应为 1,给定为 0)。
    结论: 只需翻转 yy' 的第 3 位,总翻转次数为 1。

  • 样例 3
    输入:x=01100,y=10110x'=01100, y'=10110
    若要达成合法状态,一种最少翻转方案是:

    1. 翻转 xx' 的第 1 位,使其变为 1110011100
    2. 此时合法的 yy 应为 1011110111
    3. 对比原 y=10110y'=10110,只需再翻转 yy' 的最后一位(第 5 位)。
      结论: 总共翻转了 2 次(xx' 一次,yy' 一次)。

思路讲解

yi=cimod2y_i = c_i \bmod 2,其中 cic_ixxii 个字符中 1 的个数。注意到 yiyi1=xiy_i \oplus y_{i-1} = x_i(定义 y0=0y_0 = 0。也就是说,xx 完全由 yy 决定(反之亦然)。所以你实际上只需要确定一个最终的 yy(或 xx),另一个就自动确定了。

(其实只要观察到了红字的这个约束,红字的这个东西,那么剩下来这个DP啊就非常容易了。)

1
2
3
4
5
6
vector<array<ll,2>> dp(N+2,{INF,INF});
dp[0][0]=0;
for (int i=1;i<=N;++i) {
dp[i][1]=(Y[i]!=1)+min(dp[i-1][0]+(X[i]!=1),dp[i-1][1]+(X[i]!=0));
dp[i][0]=(Y[i]!=0)+min(dp[i-1][0]+(X[i]!=0),dp[i-1][1]+(X[i]!=1));
}

AC代码

AC
https://codeforces.com/contest/2181/submission/362133326

心路历程(WA,TLE,MLE……)

题目大意

给定一个大小为n×mn \times m的表格,其中每个单元格包含0011。任务是通过一条从左上角到右下角的切割线将其分成两部分。切割线只能向右或向下走。

aa为切割后表格一部分中的1的数量,bb为表格另一部分中的1的数量。目标是最大化aba \cdot b的值。

输入

每个测试包含多个测试用例。第一行包含测试用例的数量 tt (1t1041 \le t \le 10^4)。随后是测试用例的描述。

每个测试用例的第一行包含两个整数 nnmm (1n,m31051 \leq n, m \leq 3 \cdot 10^{5}, 2nm31052 \leq n \cdot m \leq 3 \cdot 10^{5}) — 表中的行数和列数。

接下来的 nn 行中,每行包含 mm 个整数,其中第 ii 行的第 jj 个数对应值为 ai,ja_{i, j} (0ai,j10 \leq a_{i, j} \leq 1)。

保证所有测试用例中 nmn \cdot m 的总和不超过 31053 \cdot 10^{5}

输出

对于每个测试用例,在输出数据的第一行输出一个数字 - 乘积的最大值。

在第二行,输出一个由 nn 个字符 ‘D’ 和 mm 个字符 ‘R’ 组成的字符串,表示下一次切割的方向,其中 ‘D’ 表示向下切割,而 ‘R’ 表示向右切割。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
3
5 5
1 0 1 1 0
0 1 0 1 1
1 0 1 0 0
0 1 0 1 0
0 0 0 0 1
5 4
0 0 1 0
0 1 1 1
1 0 0 1
0 1 0 1
0 0 1 0
3 2
1 0
0 1
1 1

1
2
3
4
5
6
30
RDRDRDRDDR
20
DRRDRDDDR
4
DRDRD

注意

这些图片展示了第一个和第二个测试用例的正确切割方式,从而实现产品的最大价值。

image

image

思路讲解

绷不住了,我想了半天的DP解法,结果和我讲,其实这道题目根本不用DP,就贪心啊,然后这个答案总归是最大的,就是把它尽量均匀的切分成两半,总是可以的

image

是形如上图这样子切分,可以证明啊,其实也不用证明了。你直接感觉你就知道把它们尽量均匀的切分成两半是非常可行的,是完全可行的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
    for (int x=1;x<=N;++x) {
ll to_sum=sum+pre_sum[x][M];
// #ifdef LOCAL
// debug(to_sum);
// debug(sum);
// #endif
if (to_sum>=half && !is_in) {
ll bpy=1;
is_in=true;
for (ll y=M;y>=1;--y) {
sum+=maze[x][y];
if (sum==half) {
bpy=y;
break;
}
}
for (int y=1;y<bpy;++y) {
ans.push_back('R');
}
ans.push_back('D');
for (int y=bpy;y<=M;++y) {
ans.push_back('R');
}
}else {
ans.push_back('D');
}
sum=to_sum;
}

AC代码

AC

https://codeforces.com/contest/2194/submission/362089758

源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
/**
* Problem: D. Table Cut
* Contest: Codeforces Round 1078 (Div. 2)
* Judge: Codeforces
* URL: https://codeforces.com/contest/2194/problem/D
* Created: 2026-02-09 14:03:01
* Author: Gospel_rock
*
* Powered by AutoCp https://github.com/Pushpavel/AutoCp
*/

#include <bits/stdc++.h>
#define all(vec) vec.begin(),vec.end()
#define lson(o) (o<<1)
#define rson(o) (o<<1|1)
#define SZ(a) ((long long) a.size())
#define debug(var) cerr << #var <<" = ["<<var<<"]"<<"\n";
#define debug1d(a) \
cerr << #a << " = ["; \
for (int i = 0; i < (int)(a).size(); i++) \
cerr << (i ? ", " : "") << a[i]; \
cerr << "]\n";
#define debug2d(a) \
cerr << #a << " = [\n"; \
for (int i = 0; i < (int)(a).size(); i++) \
{ \
cerr << " ["; \
for (int j = 0; j < (int)(a[i]).size(); j++) \
cerr << (j ? ", " : "") << a[i][j]; \
cerr << "]\n"; \
} \
cerr << "]\n";
#define debug3d(a) \
cerr << #a << " = [\n"; \
for (int i = 0; i < (int)(a).size(); i++) \
{ \
cerr << " [\n"; \
for (int j = 0; j < (int)(a[i]).size(); j++) \
{ \
cerr << " ["; \
for (int k = 0; k < (int)(a[i][j]).size(); k++) \
cerr << (k ? ", " : "") << a[i][j][k]; \
cerr << "]\n"; \
} \
cerr << " ]\n"; \
} \
cerr << "]\n";
#define cend cerr<<"\n-----------\n"
#define fsp(x) fixed<<setprecision(x)

using namespace std;

using ll = long long;
using ull = unsigned long long;
using DB = double;
// using i128 = __int128;
using CD = complex<double>;

static constexpr ll MAXN = (ll)1e6+10, INF = (1ll<<61)-1;
static constexpr ll mod = 998244353; // (ll)1e9+7;
static constexpr double eps = 1e-8;
const double pi = acos(-1.0);

ll lT,testcase;

/*
*
*/

void Solve() {
ll N,M;
cin >> N >> M;
vector<vector<int>> maze(N+2,vector<int>(M+2));
vector<vector<ll>> pre_sum(N+2,vector<ll>(M+2));
ll sum1=0;
for (int x=1;x<=N;++x) {
for (int y=1;y<=M;++y) {
cin>>maze[x][y];
sum1+=maze[x][y];
}
}
string ans;
for (int x=1;x<=N;++x) {
partial_sum(all(maze[x]),pre_sum[x].begin());
}
ll sum=0,half=sum1/2;
bool is_in=false;
for (int x=1;x<=N;++x) {
ll to_sum=sum+pre_sum[x][M];
// #ifdef LOCAL
// debug(to_sum);
// debug(sum);
// #endif
if (to_sum>=half && !is_in) {
ll bpy=1;
is_in=true;
for (ll y=M;y>=1;--y) {
sum+=maze[x][y];
if (sum==half) {
bpy=y;
break;
}
}
for (int y=1;y<bpy;++y) {
ans.push_back('R');
}
ans.push_back('D');
for (int y=bpy;y<=M;++y) {
ans.push_back('R');
}
}else {
ans.push_back('D');
}
sum=to_sum;
}
ll a=sum1/2,b=sum1-a;
cout<<a*b<<"\n";
cout<<ans<<"\n";
#ifdef LOCAL // 校验器
if (count(all(ans),'D')==N && count(all(ans),'R')==M) {

}else {
cout<<"WA\n";
return;
}
ll col=0,row=0;
ll a_num=0,b_num=0;
for (auto ch:ans) {
if (ch=='R') {
++col;
}else {
row++;
a_num+=pre_sum[row][col];
b_num+=pre_sum[row][M]-pre_sum[row][col];
}
}
if (a_num*b_num==a*b) {

}else {
cout<<"WA\n";
}
#endif

}

signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
#ifdef LOCAL
cout.setf(ios::unitbuf); // 无缓冲流,方便我们调试
#endif

cin >> lT;
for (testcase=1;testcase<=lT;++testcase)
Solve();
return 0;
}

/*
AC
https://codeforces.com/contest/2194/submission/362089758

DRDRRD

1
3 2
1 0
0 1
1 1

_______________[ Stress test, testcase 16 INPUT ]_______________
1
1 4
0 0 0 1

_______________[ Stress test, testcase 16 OUTPUT]_______________
0
DRRRRR
WA

*/

心路历程(WA,TLE,MLE……)

题目大意

题目总结:秘密信息 (Secret message)

给定 kk 条长度均为 nn 的字符串(纸条)。你需要构造一个长度为 nn 的目标字符串 SS,满足以下要求:

  • 字符来源限制:对于 SS 中的每一个位置 ii0i<n0 \le i < n),该位置的字符必须是 kk 条纸条中第 ii 个位置出现的某一个字符。

  • 最小化信息度:字符串 SS 的“信息度” dd 必须尽可能小。

    • 信息度 dd 的定义:最小的正整数 dd,使得 SS 可以由一个长度为 dd 的字符串 tt 连续重复多次构成(即 S=t+t++tS = t + t + \dots + t)。这意味着 dd 必须是 nn 的约数。

样例解释

样例 1

输入:n=3,k=2n=3, k=2,纸条为 abcbaa

  • 位置 0 可选字符:{a, b}

  • 位置 1 可选字符:{b, a}

  • 位置 2 可选字符:{c, a}

  • 目标:尝试最小信息度 d=1d=1(即 SS 是由同一个字符重复 3 次)。

  • 检查:若 S="aaa"S = \text{"aaa"},第 0 位 ‘a’(在第一条纸条)、第 1 位 ‘a’(在第二条纸条)、第 2 位 ‘a’(在第二条纸条)均存在。因此 d=1d=1 可行。

  • 输出:aaa

样例 2

输入:n=9,k=2n=9, k=2,纸条为 iiinnnfffnnfiffinn

  • 尝试 d=1d=1:无法找到一个字符在所有 9 个位置都出现。

  • 尝试 d=3d=3:寻找长度为 3 的字符串 tt,使得 S=t+t+tS = t + t + t 满足条件。

  • 检查:若 t="inf"t = \text{"inf"},则 S="infinfinf"S = \text{"infinfinf"}

    • 第 0, 3, 6 位:‘i’ 分别在纸条 1, 2, 2 中出现。
    • 第 1, 4, 7 位:‘n’ 分别在纸条 1, 1, 1 中出现。
    • 第 2, 5, 8 位:‘f’ 分别在纸条 2, 1, 2 中出现。
  • 输出:infinfinf

样例 3

输入:n=4,k=2n=4, k=2,纸条为 acbdbdac

  • 尝试 d=1d=1:不满足。

  • 尝试 d=2d=2:寻找长度为 2 的字符串 tt,使得 S=t+tS = t + t 满足条件。

  • 检查:若 t="ac"t = \text{"ac"},则 S="acac"S = \text{"acac"}

    • 位置 0 (‘a’):在第一条。
    • 位置 1 (‘c’):在第二条。
    • 位置 2 (‘a’):在第二条。
    • 位置 3 (‘c’):在第一条。
  • 输出:acac

思路讲解

其实说白了这道题目就是想让你找一个字符串,一个字符串集的这个最小循环子串。啊,也就是找其最小循环节,但是其最小循环节呢是严格的这个最小循环节长度(即题目中的信息度),就是它不能够呃就是它不能够比如说呃roate,不能够呃循环移动的那种循环节,它是比较严格的那种循环节。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
auto check=[&](ll len,bool gen_ans=false) -> bool {
// 先生成一个长度为 len 的,每一位他能够所选的这个字符的集合(可以使用 Vector 套 bitset 表示.)。
vector<vector<int>> bi=gen_bi(0,len);
// 然后这里是不断的生成,就是继续生成这样子的集合,进行与运算的操作。
for (ll i=len;i<N;i+=len) {
bi=fac_and(bi,gen_bi(i,len));
}
for (int i=0;i<len;++i) {
bool ok=false;
for (int j=0;j<26;++j) {
if (bi[i][j]) {
if (gen_ans) {
ans.push_back('a'+j);
}
ok=true;
break;
}
}
if (!ok) {
return false;
}
}
if (gen_ans) {
string back_up=ans;
for (int i=2;i<=N/len;++i) {
ans+=back_up;
}
}
return true;
};

AC代码

https://codeforces.com/contest/2194/submission/361977470

心路历程(WA,TLE,MLE……)