BZOJ2251: [2010Beijing Wc]外星联络

本文介绍了解决BZOJ2251外星联络问题的方法,该问题是寻找信号串中重复出现的子串。文章详细解释了如何使用后缀数组和高度数组来解决这个问题。

2251: [2010Beijing Wc]外星联络

Time Limit: 30 Sec  Memory Limit: 256 MB
Submit: 989  Solved: 601
[Submit][Status][Discuss]

Description

小 P 在看过电影《超时空接触》(Contact)之后被深深的打动,决心致力于寻
找外星人的事业。于是,他每天晚上都爬在屋顶上试图用自己的收音机收听外星
人发来的信息。虽然他收听到的仅仅是一些噪声,但是他还是按照这些噪声的高
低电平将接收到的信号改写为由 0 和 1 构成的串, 并坚信外星人的信息就隐藏在
其中。他认为,外星人发来的信息一定会在他接受到的 01 串中重复出现,所以
他希望找到他接受到的 01 串中所有重复出现次数大于 1 的子串。但是他收到的
信号串实在是太长了,于是,他希望你能编一个程序来帮助他。

Input

输入文件的第一行是一个整数N ,代表小 P 接收到的信号串的长度。
输入文件第二行包含一个长度为N 的 01 串,代表小 P 接收到的信号串。

Output

输出文件的每一行包含一个出现次数大于1 的子串所出现的次数。输出的顺
序按对应的子串的字典序排列。

Sample Input

7
1010101

Sample Output

3
3
2
2
4
3
3
2
2

HINT

  对于 100%的数据,满足 0 <=  N     <=3000 

Source

 

【题解】

dalao们的题解:

“吼罪素组直接暴腻即可”

“裸题”

‘闲的没事了写一下证明吧’

。。。。。。。。。。。。。。。。。。。。。。。。。。。

此题把所有后缀提出来建一颗trie树还是比较好理解的一种做法,每个串的答案就是这个串末节点被走过的次数

后缀数组通过每个后缀的前缀来处理子串,所有后缀的每个前缀构成全部非空子串

于是我们尝试找与每个前缀相等的前缀

按字典序排序后,从小到大取,当前取到sa[i],只需从sa[i] + height[i]开始枚举前缀长度l,在排好序的后缀上向右拓展,直到到达末尾或者某个height[j]<l为止

为什么这样是对的呢?

首先你需要画一张图样例的height图,跟着调试程序模拟一下,你会有一点点想法,然后看下面本蒟蒻十分辣鸡的假证明从sa[i] + height[i]开始,因为sa[i] + height[i] - 1一定在之前遍历过。先看边界,height[k] = 0的时刻,能遍历到height[k + 1]这些串

设想如果height[i - 1] < height[i], 那么sa[i] + height[i-1]...sa[i] + height[i] - 1会被遍历;否则,无法遍历到,继续前推,肯定会到达height = 0的时刻,归纳证明可以遍历完。

为什么向后扩展不向前扩展或者双向扩展呢?因为长度大于跟前面的LCP,前面肯定没有呀。。。

大概这样。。大家可以拿图画画加深一下理解。。

如有谬误,还请原谅,毕竟。。。

我也不会很严谨的证明。。。

换了一个SA板子,从1开始的,这样跟AC自动机统一起来了,以后除KMP外所有字符串题都可以从1开始了。。

 

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cstdlib>
 5 #include <algorithm>
 6 #include <queue>
 7 #include <vector>
 8 #include <cmath> 
 9 #define min(a, b) ((a) < (b) ? (a) : (b))
10 #define max(a, b) ((a) > (b) ? (a) : (b))
11 #define abs(a) ((a) < 0 ? (-1 * (a)) : (a))
12 
13 template <class T>
14 inline void swap(T& a, T& b)
15 {
16     T tmp = a;a = b;b = tmp;
17 }
18 
19 const int INF = 0x3f3f3f3f;
20 const int MAXN = 1000000 + 10;
21 
22 struct SuffixArray
23 {
24     char s[MAXN];
25     int sa[MAXN], rank[MAXN], height[MAXN];
26     int t1[MAXN], t2[MAXN], c[MAXN];
27     int n;
28     void build_sa(int m)
29     {
30         int i, *x = t1, *y = t2;
31         for(i = 0;i <= m;++ i) c[i] = 0;
32         for(i = 1;i <= n;++ i) ++ c[x[i] = s[i]];
33         for(i = 1;i <= m;++ i) c[i] += c[i - 1];
34         for(i = n;i >= 1;-- i) sa[c[x[i]] --] = i;
35         for(int k = 1;k <= n;k <<= 1)
36         {
37             int p = 0;
38             for(i = n - k + 1;i <= n;++ i) y[++ p] = i;
39             for(i = 1;i <= n;++ i) if(sa[i] > k) y[++ p] = sa[i] - k;
40             for(i = 0;i <= m;++ i) c[i] = 0;
41             for(i = 1;i <= n;++ i) ++ c[x[y[i]]];
42             for(i = 1;i <= m;++ i) c[i] += c[i - 1];
43             for(i = n;i >= 1;-- i) sa[c[x[y[i]]] --] = y[i];
44             swap(x, y);p = 0,x[sa[1]] = ++ p;
45             for(i = 2;i <= n;++ i)
46                 x[sa[i]] = sa[i] + k <= n && sa[i - 1] + k <= n && y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k] ? p : ++ p;
47             if(p >= n) break;m = p;
48         }
49     }
50     void build_height()
51     {
52         int i, k = 0;
53         for(i = 1;i <= n;++ i) rank[sa[i]] = i;
54         for(i = 1;i <= n;++ i)
55         {
56             if(k) -- k; if(rank[i] == 1) continue;
57             int j = sa[rank[i] - 1];
58             while(i + k <= n && j + k <= n && s[i + k] == s[j + k]) ++ k;
59             height[rank[i]] = k;
60         }
61     }
62 }A;
63 
64 int n;
65 
66 int main()
67 {
68     scanf("%d", &n);
69     scanf("%s", A.s + 1);
70     A.n = n;
71     A.build_sa('1');
72     A.build_height();
73     int k;
74     for(int i = 1;i <= n;++ i)
75         for(int j = A.sa[i] + A.height[i];j <= n;++ j)
76         {
77             for(k = i;A.height[k + 1] >= j - A.sa[i] + 1;++ k);
78             if(k - i + 1 > 1) printf("%d\n", k - i + 1);
79         }
80                 
81 }
BZOJ2251

 

转载于:https://www.cnblogs.com/huibixiaoxing/p/8333823.html

### 光流法C++源代码解析与应用 #### 光流法原理 光流法是一种在计算机视觉领域中用于追踪视频序列中运动物体的方法。它基于亮度不变性假设,即场景中的点在时间上保持相同的灰度值,从而通过分析连续帧之间的像素变化来估计运动方向和速度。在数学上,光流场可以表示为像素位置和时间的一阶导数,即Ex、Ey(空间梯度)和Et(时间梯度),它们共同构成光流方程的基础。 #### C++实现细节 在给定的C++源代码片段中,`calculate`函数负责计算光流场。该函数接收一个图像缓冲区`buf`作为输入,并初始化了几个关键变量:`Ex`、`Ey`和`Et`分别代表沿x轴、y轴和时间轴的像素强度变化;`gray1`和`gray2`用于存储当前帧和前一帧的平均灰度值;`u`则表示计算出的光流矢量大小。 #### 图像处理流程 1. **初始化和预处理**:`memset`函数被用来清零`opticalflow`数组,它将保存计算出的光流数据。同时,`output`数组被填充为白色,这通常用于可视化结果。 2. **灰度计算**:对每一像素点进行处理,计算其灰度值。这里采用的是RGB通道平均值的计算方法,将每个像素的R、G、B值相加后除以3,得到一个近似灰度值。此步骤确保了计算过程的鲁棒性和效率。 3. **光流向量计算**:通过比较当前帧和前一帧的灰度值,计算出每个像素点的Ex、Ey和Et值。这里值得注意的是,光流向量的大小`u`是通过`Et`除以`sqrt(Ex^2 + Ey^2)`得到的,再乘以10进行量化处理,以减少计算复杂度。 4. **结果存储与阈值处理**:计算出的光流值被存储在`opticalflow`数组中。如果`u`的绝对值超过10,则认为该点存在显著运动,因此在`output`数组中将对应位置标记为黑色,形成运动区域的可视化效果。 5. **状态更新**:通过`memcpy`函数将当前帧复制到`prevframe`中,为下一次迭代做准备。 #### 扩展应用:Lukas-Kanade算法 除了上述基础的光流计算外,代码还提到了Lukas-Kanade算法的应用。这是一种更高级的光流计算方法,能够提供更精确的运动估计。在`ImgOpticalFlow`函数中,通过调用`cvCalcOpticalFlowLK`函数实现了这一算法,该函数接受前一帧和当前帧的灰度图,以及窗口大小等参数,返回像素级别的光流场信息。 在实际应用中,光流法常用于目标跟踪、运动检测、视频压缩等领域。通过深入理解和优化光流算法,可以进一步提升视频分析的准确性和实时性能。 光流法及其C++实现是计算机视觉领域的一个重要组成部分,通过对连续帧间像素变化的精细分析,能够有效捕捉和理解动态场景中的运动信息
微信小程序作为腾讯推出的一种轻型应用形式,因其便捷性与高效性,已广泛应用于日常生活中。以下为该平台的主要特性及配套资源说明: 特性方面: 操作便捷,即开即用:用户通过微信内搜索或扫描二维码即可直接使用,无需额外下载安装,减少了对手机存储空间的占用,也简化了使用流程。 多端兼容,统一开发:该平台支持在多种操作系统与设备上运行,开发者无需针对不同平台进行重复适配,可在一个统一的环境中完成开发工作。 功能丰富,接口完善:平台提供了多样化的API接口,便于开发者实现如支付功能、用户身份验证及消息通知等多样化需求。 社交整合,传播高效:小程序深度嵌入微信生态,能有效利用社交关系链,促进用户之间的互动与传播。 开发成本低,周期短:相比传统应用程序,小程序的开发投入更少,开发周期更短,有助于企业快速实现产品上线。 资源内容: “微信小程序-项目源码-原生开发框架-含效果截图示例”这一资料包,提供了完整的项目源码,并基于原生开发方式构建,确保了代码的稳定性与可维护性。内容涵盖项目结构、页面设计、功能模块等关键部分,配有详细说明与注释,便于使用者迅速理解并掌握开发方法。此外,还附有多个实际运行效果的截图,帮助用户直观了解功能实现情况,评估其在实际应用中的表现与价值。该资源适用于前端开发人员、技术爱好者及希望拓展业务的机构,具有较高的参考与使用价值。欢迎查阅,助力小程序开发实践。资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值