Jewel Magic UVA - 11996 || bzoj1014: [JSOI2008]火星人prefix
这是一道用splay/非旋treap做的题(这里用的是非旋treap)
1/2/3是splay/非旋treap的常规操作。对于操作4,可以用哈希法求LCP。记hash(i,L)为子串[i,i+L-1](即第i个开始的L个)的hash值。记s[i]为序列第i位(编号从1开始),n为序列长度
如果通过某种方式做到能在O(logn)时间内取出一段子串的hash值,那么二分答案(即LCP长度x),可以在O(logn)时间内判一个x是否合法(如果hash(l,x)==hash(r,x)则认为[l,l+x-1]和[r,r+x-1]是相同的,合法,否则不合法),可以做到在O(log^2n)内完成一个操作4。当然,hash判字符串是否相同正确性可能受影响,因此可以多计算一些hash,当他们都相同时才认为字符串相同,可以将错误率降到足够小。
如何维护一段子串的hash值?首先定义x为任意整数,定义$hash(i,L)=s[i+L-1]*x^{L-1}+s[i+L-2]*x^{L-2}+...+s[i+1]*x+s[i]$
(这里及之后都省略了取模)
(简单记法:左边乘的次数小)
(另一种记法:另一种求法的伪代码表示:ans=0;for(j=i+L-1;j>=i;j--) ans=ans*x+s[j];)
可以发现:如果已知hash(i,p)和hash(i+p,q)(即已知[i,i+p-1]和[i+p,i+p+q-1]的hash值),要求hash(i,p+q)(就是这两段合起来的hash值),那么:
令j=i+p,那么$hash(i,p+q)$
$=s[j+q-1]*x^{p+q-1}+s[j+q-2]*x^{p+q-2}+...+s[j]*x^p+s[i+p-1]*x^{p-1}+...+s[i]*x^0$
所以$hash(i,p+q)=hash(j,q)*x^p+hash(i,p)=hash(i,p)+hash(i+p,q)*x^p$
这样就得到了对于平衡树某个节点,根据子节点为根的子树的hash值与自身值求以自身为根的子树的hash值的方法(先将左子树和自身合起来,再将结果与右子树合起来)
当然,由于此题有一个翻转操作,对于一个节点要维护两个hash:正向序列hash和反向序列hash。翻转操作时顺便交换一下两个的值。
附:这道题没有卡hash,单hash就能过,
附:听说操作4有O(logn)的方法?待解决
错误记录:
1.141行误用build函数(build是用的左闭右闭区间),输入了(a+1,a+n+1)。(然而不知道为什么虽然过不了udebug的数据然而把题目A掉了)
2.没注意在字符前还是字符后插入
*3.posib函数写错:没有考虑要计算hash值的串超出长度范围的情况(就是第二个"&&"之前的部分)。错了不止一次
4.可能出现的错误:如果hash不用ull自然溢出,自己取模,那么要考虑爆int、爆longlong、负数等等
- #include<cstdio>
- #include<algorithm>
- using namespace std;
- inline int rand1()
- {
- static int x=;
- return x=(48271LL*x+)%;
- }
- unsigned long long powx[];
- struct Node
- {
- Node(){}
- Node* ch[];
- int r;
- bool flip;
- int v;
- unsigned long long h,rh;
- int size;
- void upd()
- {
- if(ch[]) ch[]->pd();
- if(ch[]) ch[]->pd();
- size=+(ch[]?ch[]->size:)+(ch[]?ch[]->size:);
- h=(ch[]?ch[]->h:)+v*powx[ch[]?ch[]->size:]+(ch[]?ch[]->h:)*powx[(ch[]?ch[]->size:)+];
- rh=(ch[]?ch[]->rh:)+v*powx[ch[]?ch[]->size:]+(ch[]?ch[]->rh:)*powx[(ch[]?ch[]->size:)+];
- }
- void pd()
- {
- if(flip)
- {
- swap(ch[],ch[]);
- swap(h,rh);
- if(ch[]) (ch[]->flip)^=;
- if(ch[]) (ch[]->flip)^=;
- flip=;
- }
- }
- }nodes[];
- Node* root;int mem;
- Node* getnode(){return nodes+(mem++);}
- Node* merge(Node* a,Node* b)
- {
- if(a==NULL) return b;
- if(b==NULL) return a;
- if(a->r < b->r)
- {
- a->pd();a->ch[]=merge(a->ch[],b);a->upd();
- return a;
- }
- else
- {
- b->pd();b->ch[]=merge(a,b->ch[]);b->upd();
- return b;
- }
- }
- typedef pair<Node*,Node*> P;
- P split(Node* a,int n)
- {
- if(a==NULL) return P(NULL,NULL);
- P y;
- a->pd();int s=a->ch[] ? a->ch[]->size : ;
- if(s>=n)
- {
- y=split(a->ch[],n);
- a->ch[]=y.second;a->upd();
- y.second=a;
- }
- else
- {
- y=split(a->ch[],n-s-);
- a->ch[]=y.first;a->upd();
- y.first=a;
- }
- return y;
- }
- inline void insert(int k,int x)
- {
- Node* t=getnode();
- t->ch[]=t->ch[]=NULL;t->r=rand1();t->v=x;t->flip=;t->upd();
- P y=split(root,k-);
- root=merge(merge(y.first,t),y.second);
- }
- inline void erase(int k)
- {
- P y=split(root,k-);
- P y2=split(y.second,);
- root=merge(y.first,y2.second);
- }
- inline void reverse(int l,int r)
- {
- if(l>r) swap(l,r);
- P y=split(root,l-);
- P y2=split(y.second,r-l+);
- y2.first->flip^=;
- root=merge(merge(y.first,y2.first),y2.second);
- }
- inline int size()
- {
- return root ? root->size : ;
- }
- inline unsigned long long geth(int l,int r)
- {
- if(l>r) return ;
- P y=split(root,l-);
- P y2=split(y.second,r-l+);
- unsigned long long ans=y2.first ? y2.first->h : ;
- root=merge(merge(y.first,y2.first),y2.second);
- return ans;
- }
- Node* build(int *l,int *r)
- {
- if(l>r) return NULL;
- if(l==r)
- {
- Node* t=getnode();
- t->ch[]=t->ch[]=NULL;t->r=rand1();t->v=*l;t->flip=;t->upd();
- return t;
- }
- else
- {
- int* mid=l+(r-l)/;
- return merge(build(l,mid),build(mid+,r));
- }
- }
- int n,m,q;
- int a[];
- const int X=;
- int l,r;
- inline bool posib(int x)
- {
- return (l+x-<=size())&&(r+x-<=size())&&(geth(l,l+x-)==geth(r,r+x-));
- }
- int main()
- {
- register int i;
- int lx,rx,k,x,mid,tmp;
- powx[]=;
- for(i=;i<=;i++) powx[i]=powx[i-]*X;
- scanf("%d%d",&n,&q);
- for(i=;i<=n;i++) scanf("%1d",&a[i]);
- root=build(a+,a+n);
- while(q--)
- {
- scanf("%d",&tmp);
- if(tmp==)
- {
- scanf("%d%d",&k,&x);
- insert(k+,x);
- }
- else if(tmp==)
- {
- scanf("%d",&k);
- erase(k);
- }
- else if(tmp==)
- {
- scanf("%d%d",&l,&r);
- reverse(l,r);
- }
- else if(tmp==)
- {
- scanf("%d%d",&l,&r);
- lx=;rx=size()+;
- while(rx-lx>)
- {
- mid=(lx+rx)>>;
- if(posib(mid)) lx=mid;
- else rx=mid;
- }
- printf("%d\n",lx);
- }
- }
- return ;
- }
https://www.lydsy.com/JudgeOnline/problem.php?id=1014
https://www.luogu.org/problemnew/show/P4036
贴一下常数超大的代码
做法类似
- #pragma GCC optimize("Ofast")
- #include<cstdio>
- #include<algorithm>
- #include<cstring>
- using namespace std;
- inline int rand1()
- {
- static int x=;
- return x=(48271LL*x+)%;
- }
- unsigned long long powx[];
- struct Node
- {
- Node(){}
- Node* ch[];
- int r;
- int v;
- unsigned long long h;
- int size;
- void upd()
- {
- size=+(ch[]?ch[]->size:)+(ch[]?ch[]->size:);
- h=(ch[]?ch[]->h:)+v*powx[ch[]?ch[]->size:]+(ch[]?ch[]->h:)*powx[(ch[]?ch[]->size:)+];
- }
- }nodes[];
- Node* root;int mem;
- Node* getnode(){return nodes+(mem++);}
- Node* merge(Node* a,Node* b)
- {
- if(a==NULL) return b;
- if(b==NULL) return a;
- if(a->r < b->r)
- {
- a->ch[]=merge(a->ch[],b);a->upd();
- return a;
- }
- else
- {
- b->ch[]=merge(a,b->ch[]);b->upd();
- return b;
- }
- }
- typedef pair<Node*,Node*> P;
- P split(Node* a,int n)
- {
- if(a==NULL) return P(NULL,NULL);
- P y;
- int s=a->ch[] ? a->ch[]->size : ;
- if(s>=n)
- {
- y=split(a->ch[],n);
- a->ch[]=y.second;a->upd();
- y.second=a;
- }
- else
- {
- y=split(a->ch[],n-s-);
- a->ch[]=y.first;a->upd();
- y.first=a;
- }
- return y;
- }
- inline void insert(int k,int x)
- {
- Node* t=getnode();
- t->r=rand1();t->v=x;t->upd();
- P y=split(root,k-);
- root=merge(merge(y.first,t),y.second);
- }
- inline void erase(int k)
- {
- P y=split(root,k-);
- P y2=split(y.second,);
- root=merge(y.first,y2.second);
- }
- inline int size()
- {
- return root ? root->size : ;
- }
- inline unsigned long long geth(int l,int r)
- {
- if(l>r) return ;
- P y=split(root,l-);
- P y2=split(y.second,r-l+);
- unsigned long long ans=y2.first ? y2.first->h : ;
- root=merge(merge(y.first,y2.first),y2.second);
- return ans;
- }
- Node* build(char *l,char *r)
- {
- if(l>r) return NULL;
- if(l==r)
- {
- Node* t=getnode();
- t->r=rand1();t->v=(int)(*l);t->upd();
- return t;
- }
- else
- {
- char* mid=l+(r-l)/;
- return merge(build(l,mid),build(mid+,r));
- }
- }
- int n,m,q;
- char a[];
- const int X=;
- int l,r;
- char tmp;
- inline bool posib(int x)
- {
- return (l+x-<=size())&&(r+x-<=size())&&(geth(l,l+x-)==geth(r,r+x-));
- }
- int main()
- {
- register int i;
- int lx,rx,k,mid;
- powx[]=;
- for(i=;i<=;i++) powx[i]=powx[i-]*X;
- scanf("%s",a+);n=strlen(a+);
- root=build(a+,a+n);
- scanf("%d",&q);
- while(q--)
- {
- tmp=getchar();while(tmp<'A'||tmp>'Z') tmp=getchar();
- if(tmp=='I')
- {
- scanf("%d",&k);tmp=getchar();while(tmp<'a'||tmp>'z') tmp=getchar();
- insert(k+,(int)tmp);
- }
- else if(tmp=='R')
- {
- scanf("%d",&k);tmp=getchar();while(tmp<'a'||tmp>'z') tmp=getchar();
- erase(k);insert(k,(int)tmp);
- }
- else if(tmp=='Q')
- {
- scanf("%d%d",&l,&r);
- lx=;rx=size()+;
- while(rx-lx>)
- {
- mid=(lx+rx)>>;
- if(posib(mid)) lx=mid;
- else rx=mid;
- }
- printf("%d\n",lx);
- }
- }
- return ;
- }
Jewel Magic UVA - 11996 || bzoj1014: [JSOI2008]火星人prefix的更多相关文章
- [BZOJ1014][JSOI2008]火星人prefix
[BZOJ1014][JSOI2008]火星人prefix 试题描述 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字 ...
- BZOJ1014 JSOI2008 火星人prefix 【非旋转Treap】*
BZOJ1014 JSOI2008 火星人prefix Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符 ...
- 2018.06.28 BZOJ1014 [JSOI2008]火星人prefix(非旋treap+hash)
[JSOI2008]火星人prefix Time Limit: 10 Sec Memory Limit: 162 MB Submit: 8951 Solved: 2860 Description 火星 ...
- bzoj千题计划106:bzoj1014 [JSOI2008]火星人prefix
http://www.lydsy.com/JudgeOnline/problem.php?id=1014 两个后缀的最长公共前缀:二分+hash 带修改带插入:splay维护 #include< ...
- [BZOJ1014] [JSOI2008] 火星人prefix (splay & 二分答案)
Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 ...
- bzoj1014: [JSOI2008]火星人prefix splay+hash+二分
Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 ...
- [bzoj1014](JSOI2008)火星人 prefix (Splay维护哈希)
Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀. 比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 ...
- BZOJ1014[JSOI2008]火星人prefix(splay维护hash)
Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 ...
- BZOJ1014: [JSOI2008]火星人prefix(splay 二分 hash)
题意 题目链接 Sol 一眼splay + 二分hash,不过区间splay怎么写来着呀 试着写了两个小时发现死活不对 看了一下yyb的代码发现自己根本就不会splay.... // luogu-ju ...
随机推荐
- 火狐浏览器Firefox 如何下载网页的SWF视频,硅谷动力的网站视频怎么下载
1 使用火狐浏览器查看到底视频在哪里,我随便开了一段视频,发现这个SWF(外框套了一个Control.swf,内层才是真实的09-class.swf) 2 我们从下面这一段代码中进行分析 < ...
- iOS开发--常用技巧 (MJRefresh详解)
iOS开发--常用技巧 (MJRefresh详解) https://github.com/CoderMJLee/MJRefresh 下拉刷新01-默认 self.tableView.head ...
- Codeforces 768 E. Game of Stones 博弈DP
E. Game of Stones Sam has been teaching Jon the Game of Stones to sharpen his mind and help him de ...
- 解决手淘lib-flexible.js在移动端首次加载页面页面先放大后正常问题
例如这样 然后这样 出现这样的原因一般是 静态的,即html里有一些静态的(即非js动态添加的) 如果在页面加载完成后,页面是用js动态添加的,这个问题就不太明显, doc.addEventLis ...
- easyUI下拉列表点击事件的使用
可以通过input 和select来创建下拉列表 其中select的创建如下: 通过json来创建js数组 [{ "id":1, "text":"te ...
- YTU 2574: 空白格式化
2574: 空白格式化 时间限制: 1 Sec 内存限制: 128 MB 提交: 233 解决: 118 题目描述 恭喜你进入了蓝桥杯总决赛,本次大赛采用了全自动机器测评系统. 如果你的答案与标准 ...
- [QT开发小结]LNK1104: cannot open file ‘gdi32.lib’ 解决方法
1.环境变量 : Path = ;C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Bin; 添加变量: INCLUDE = C:\Program ...
- 解决安装YII2 速度慢 失败等问题
更改composer镜像地址为 composer config -g repo.packagist composer https://packagist.phpcomposer.com
- codeforces 686C C. Robbers' watch(dfs)
题目链接: C. Robbers' watch time limit per test 2 seconds memory limit per test 256 megabytes input stan ...
- 使用Python操作Redis应用场景
1. 安装pyredis 首先安装pip 1 2 3 4 5 6 7 8 <SHELL># apt-get install python-pip ...... <SHELL> ...