[GDOI模拟2015.08.18]解密
来源:互联网 发布:matlab编程题 编辑:程序博客网 时间:2024/06/05 16:35
题目大意
给定一篇由若干个单词构成的原文,还有一个由若干个单词组成的句子。加密文是由原文单词通过某个单词(可能一样)替换而成的,原文相同单词一定会被相同加密文单词替换。没有两个不同的原文单词被同一个加密文单词替换。
要求找出句子在加密文中第一次出现的位置。
原文字符总和不超过
题目分析
这题一看就大概知道是字符串的模式匹配问题。正解是用最小表示法表示字符串,然后上KMP或是HASH。
我比赛时想了一个比较另类的方法。我们将原文第
这个时候能否直接上KMP算法呢?我们可以发现一个很显然的反例。记原文为
这种能模式串随匹配串位置改变的KMP我没有YY出来,于是我打了个HASH。我们发现,如果我们顺序枚举匹配位置,每个原文单词值最多会变化两次(从
感觉讲得很乱,不懂的就看看代码实现吧。处理后继
代码实现
#include <iostream>#include <cstring>#include <cstdlib>#include <cstdio>#include <ctime>using namespace std;typedef long long LL;const int N=1000000;int seed[4][3]={{314351,8761,155921},{180503,6899,935381},{78101,59659,414977},{9999889,1000000007,9876809}};char article[N+1],sentence[N+1];int aword[N+2],sword[N+2];int power[3][N+1];int succ[2][N+1];char temp[N+1];int sthash[3];int prime[4];int n,m,ans,as,ss;struct TRIE{ int tov[N+1],next[N+1],ch[N+1]; int last[N+1],key[N+1]; int etot,ptot,root; void init() { memset(next,0,sizeof next); memset(last,0,sizeof last); memset(key,0,sizeof key); etot=ptot=0; } void insert(int len,int pos,int kind) { int rt=root?root:root=++ptot; bool found; int i,y; for (int l=0;l<len;l++) { found=false; i=last[rt]; while (i) { y=tov[i]; if (ch[i]==temp[l]-'a'+1) { found=true; break; } i=next[i]; } if (found) rt=y; else { key[++ptot]=0; tov[++etot]=ptot; ch[etot]=temp[l]-'a'+1; next[etot]=last[rt]; last[rt]=etot; rt=ptot; } } if (key[rt]) succ[kind][key[rt]]=pos-key[rt]; key[rt]=pos; }}trie;void hang(int x,int y){ trie.tov[++trie.etot]=y; trie.next[trie.etot]=trie.last[x]; trie.last[x]=trie.etot;}void read(){ n=m=0; char ch=getchar(); int la=0; while (ch!='$') { while ((ch<'a'||ch>'z')&&ch!='$') { if (ch==' ') aword[++as]=la; ch=getchar(); } if (ch>='a'&&ch<='z') la=n; while (ch>='a'&&ch<='z') { article[n++]=ch; ch=getchar(); } } aword[as+1]=n; article[n]='\0'; ch=getchar(); la=0; while (ch!='$') { while ((ch<'a'||ch>'z')&&ch!='$') { if (ch==' ') sword[++ss]=la; ch=getchar(); } if (ch>='a'&&ch<='z') la=m; while (ch>='a'&&ch<='z') { sentence[m++]=ch; ch=getchar(); } } sword[ss+1]=m; sentence[m]='\0';}void preparation(){ int len; for (int i=1;i<=as;i++) { len=0; for (int j=aword[i];j<aword[i+1];j++) temp[len++]=article[j]; temp[len]='\0'; trie.insert(len,i,0); } trie.init(); for (int i=1;i<=ss;i++) { len=0; for (int j=sword[i];j<sword[i+1];j++) temp[len++]=sentence[j]; temp[len]='\0'; trie.insert(len,i,1); } trie.init(); for (int i=1;i<=as;i++) if (succ[0][i]) hang(i+succ[0][i],i); srand(time(0)); for (int i=0;i<4;i++) prime[i]=seed[i][rand()%3]; for (int i=0;i<3;i++) { power[i][0]=1; for (int j=1;j<=n;j++) power[i][j]=(LL)power[i][j-1]*prime[i]%prime[3]; sthash[i]=0; for (int j=1;j<=ss;j++) sthash[i]=(((LL)sthash[i]*prime[i])%prime[3]+succ[1][j])%prime[3]; }}void solve(){ int hash[3]={0},item,ptr; for (int i=1;i<=ss-1;i++) for (int j=0;j<3;j++) { hash[j]=(LL)hash[j]*prime[j]%prime[3]; hash[j]=((LL)hash[j]+(succ[0][i]+i>i?0:succ[0][i]))%prime[3]; ptr=trie.last[i]; while (ptr) { item=trie.tov[ptr]; hash[j]=((LL)hash[j]+((LL)power[j][i-item]*succ[0][item])%prime[3])%prime[3]; ptr=trie.next[ptr]; } } int la=1,tmp; for (int i=ss;i<=as;i++) { for (int j=0;j<3;j++) { hash[j]=(LL)hash[j]*prime[j]%prime[3]; hash[j]=((LL)hash[j]+(succ[0][i]+i>i?0:succ[0][i]))%prime[3]; ptr=trie.last[i]; while (ptr) { item=trie.tov[ptr]; if (item>=i-ss+1) hash[j]=((LL)hash[j]+((LL)power[j][i-item]*succ[0][item])%prime[3])%prime[3]; ptr=trie.next[ptr]; } } if (hash[0]==sthash[0]&&hash[1]==sthash[1]&&hash[2]==sthash[2]) { ans=i-ss+1; break; } tmp=succ[0][i-ss+1]+i-ss+1>i?0:succ[0][i-ss+1]; for (int j=0;j<3;j++) hash[j]=(((LL)hash[j]-((LL)tmp*power[j][ss-1]%prime[3]))%prime[3]+prime[3])%prime[3]; }}int main(){ freopen("decryption.in","r",stdin); freopen("decryption.out","w",stdout); read(); preparation(); solve(); printf("%d\n",ans); fclose(stdin); fclose(stdout); return 0;}
无谓扯淡
看到这题,其实大家都想到什么。当然,就是OJ的代码相似度判断。我脑补了一下,OJ其实可以将代码缩进回车空格删除,拆成若干表达式和句子,然后用这题算法的改进版来判断相似度(大神勿喷)。
- [GDOI模拟2015.08.18]解密
- [GDOI模拟2015.08.08]排列
- GDOI 3.21 模拟总结
- 【GDOI】模拟8.1总结
- 【GDOI】模拟8.2总结
- 【GDOI】模拟8.3总结
- GDOI模拟8.1
- 【GDOI 2013模拟】屏保
- GDOI模拟 20150806
- GDOI模拟8.6总结
- GDOI模拟8.7总结
- 【GDOI 2013模拟】Processer
- GDOI模拟 蜘蛛侠
- 【GDOI 2013模拟】总结
- gdoi 8.20模拟总结
- GDOI 8.21模拟
- GDOI模拟8.21总结
- GDOI模拟 2.26
- POJ 1321 棋盘问题(深搜)
- Java技术资料
- [LeetCode] Search a 2D Matrix(二分查找)
- Part1. OSGi的优势和可能遇到的问题
- C# 之 FTP服务器中文件上传与下载(二)
- [GDOI模拟2015.08.18]解密
- C++ Primer 5e chapter 14.1
- java实现ArrayList LinkedList 和迭代器
- C/C++头文件注释
- CCActionGird3D源码解析
- (2.1.20)java中的进程
- 【BZOJ1212】【HNOI2004】L语言
- Deep Learning及NLP(自然语言处理)杂谈--第三部分
- 黑马程序员 --- OC中的类