放爆竹

题目大意:有n个初始字符串,由这n个初始字符串延伸出实际字符串。

每个实际字符串为初始字符串循环后得到。字符集为 {0,1}。如初始字符串 01,循环后得到实际字符串 01010101…。求n个实际字符串中任意两个串的最长公共前缀。第i个初始字符串的长度小于500。保证每个初始字符串都不存在周期。其中n属于20000.

一个很显然的思路:既然只有01,那么我们分治来做,对于每一位,是0的分一堆儿,是1的分一堆儿

然后分到最后,l=r的时候,分到了哪一位就是最长的公共前缀,然后每个都取max

注意:一定要提前处理好字符串的长度,不可边算边处理

hack数据:

10与101

如果先排序后处理的话,会得到:10,101

如果先处理后排序的话,会得到101,10(10)

这就是tm20pts与100pts的区别

代码如下:

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
#include <bits/stdc++.h>
using namespace std;

const int N = 2e4 + 66, inf = 214748364;

int n, res; string s[N];

inline void solve(int x, int l, int r)
{
if (l == r) return (void)(res = max(res, x - 1));
int i, mid = -inf;
for (i = l + 1; i <= r; ++ i)
{
if (s[i][x] != s[i - 1][x])
{
mid = i - 1;
break;
}
}
if (mid != -inf) solve(x + 1, l, mid), solve(x + 1, mid + 1, r);
else solve(x + 1, l, r);
return;
}

signed main()
{
int i; n = read();
for (i = 1; i <= n; ++ i)
{
getline(cin, s[i]);
string a = s[i];
while ((s[i].length() + a.length()) <= 1000) s[i] += a;
}
sort(s + 1, s + n + 1), solve(0, 1, n);
put(res);

fclose(stdin), fclose(stdout);
return 0;
}

总结:细节决定成败,我今天的经历仿佛一场梦,从第一到倒数,无法预料

还是要以积极的态度面对生活,放下分数,拿起知识,尽人事,听天命,面临CSP-S最后一个月,冲冲冲!