很久之前做的一题,忽然想起来,依然觉得思路巧妙。

//这道题,确实是一道好题。但如何应用KMP,确实大大超出了意料中。
//这道题匹配的是某元素在子串中的名次,也就是在子串中排第几小。我想了整整一天,才想到一个较好
//的方法来确定在子串中的位置,本来以为可以用这个来暴力枚举再加剪枝可以过,但没想到。。TLE //代码是转的,算法也是看过别人的才懂。
//好吧,看过别人的解题,写的代码不难,算法特别难想。首先统计在位置I的元素之前,比该元素小的个数
//以及和该元素相等的个数,这个我用暴力枚举来预处理,也有用树状数组的,但我看不懂。然后重新修改
//匹配的定义:假设前N-1个元素匹配,则第N个元素匹配的条件是该元素之前的(当然必须是在子串范围内)
//小于与等于该元素的个数都分别相等。我试图否定它,但总感觉是显而易见的,可我没想到。接下来就可以
//据此来求NEXT函数了。在求NEXT时,必须注意是要求N-1个元素中小于与等于N元素的个数分别相等。 //我想做一次事后诸葛亮(虽然本人不是什么牛人),总结一下:
//我觉得,以后遇到配匹模式串的题应该都可以用KMP来解题,真心觉得KMP是十分的一个算法。但在应用NEXT
//函数时,应适当改一下定义,怎么改呢?我认为,要求某位置的NEXT的值,应该首先满足的条件时,该位置
//之前的字符或数已匹配,所以,应当先假设前N个元素匹配,再给出N+1个元素匹配的条件,且应该是无须
//理会N+1之后的影响的。这样就可以进行KMP了。 #include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std; int n,k,s; struct TT
{
int len;
int num[];
int low[][],equ[][];
} t,p; void init(TT &tmp)
{
for(int i =;i<=tmp.len;i++)
{
for(int j = ;j<=s;j++)
{
tmp.low[i][j] = tmp.low[i-][j] + (tmp.num[i] < j ? : );
tmp.equ[i][j] = tmp.equ[i-][j] + (tmp.num[i] == j ? : );
}
}
} int fail[]; int check(TT &a,TT &b,int i,int j)
{
if(a.low[i][a.num[i]] - a.low[i - j][a.num[i]] == b.low[j][b.num[j]]
&& a.equ[i][a.num[i]] - a.equ[i - j][a.num[i]] == b.equ[j][b.num[j]])
return ;
return ;
} void get_fail()
{
fail[] = ;
int j = ;
for(int i = ;i<=k;i++)
{
if(j >= && !check(p,p,i,j+) )
j = fail[j];
if(check(p,p,i,j+)) j++;
fail[i] = j;
}
} vector <int> ans; void kmp()
{
ans.clear();
get_fail();
int j = ;
for(int i = ;i<=n;i++)
{
while(j >= && !check(t,p,i,j+)) j = fail[j];
if(check(t,p,i,j+)) j++; if(j == k)
{
ans.push_back(i-k+);
j = fail[j];
}
}
} int main()
{
while(~scanf("%d%d%d",&n,&k,&s))
{
for(int i = ;i<=n;i++)
scanf("%d",&t.num[i]);
for(int i = ;i<=k;i++)
scanf("%d",&p.num[i]);
t.len = n;
p.len = k;
init(t);
init(p);
kmp();
printf("%d\n",ans.size());
for(int i = ;i<ans.size();i++)
printf("%d\n",ans[i]);
}
return ;
}

最新文章

  1. debian下使用Sphinx异常“Could not import extension sphinx.builders.linkcheck (exception: cannot import name SSLError)”的解决
  2. &lt;转&gt;[WinForm] VS2010发布、打包安装程序(超全超详细)
  3. repeater留言板[转]
  4. uC/OS-II任务(OS_task)块
  5. linux命令介绍:df使用介绍
  6. jquery uploadify上传插件兼容火狐问题
  7. program
  8. 【转】.. Android应用内存泄露分析、改善经验总结
  9. css图片映射
  10. linux mkfs命令参数及用法详解---linux格式化文件系统命令(包括swap分区)
  11. c语言中文件相关操作
  12. jQuery作用
  13. Linux网卡驱动架构分析
  14. 第一个Android crackme(2016-05)
  15. iOS 将NSArray、NSDictionary转换为JSON格式进行网络传输
  16. JDK源码分析-Integer
  17. #define WIN32_LEAN_AND_MEAN
  18. 【学习笔记】node.js重构路由功能
  19. c# 后台post,包含file文件
  20. 第11章 拾遗5:IPv6和IPv4共存技术(2)_ISATAP隧道技术

热门文章

  1. SpringBoot入门之HelloWorld
  2. Android 关于android.os.Build介绍
  3. android:autoLink
  4. Struts2 之 实现文件上传(多文件)和下载
  5. 【转】Java 集合系列12之 TreeMap详细介绍(源码解析)和使用示例
  6. iis设置404错误页,返回500状态码
  7. 使用Jupter Notebook实现简单的神经网络
  8. SQL基本操作——日期函数
  9. (转) Hibernate框架基础——操纵持久化对象的方法(Session中)
  10. IntelliJ IDEA之windows下载安装、卸载