[bzoj4516] [Sdoi2016]生成魔咒
2016-06-19 15:51
615 查看
强行上hash。。复杂度两个log。。
把字符串倒过来。就是每次加一个后缀。。就变成问一个后缀会产生多少个不同子串的板子题了。
听说是SAM板子题..这辈子学不会SAM系列>_<
View Code
把字符串倒过来。就是每次加一个后缀。。就变成问一个后缀会产生多少个不同子串的板子题了。
听说是SAM板子题..这辈子学不会SAM系列>_<
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #define ll long long #define ull unsigned long long using namespace std; const int maxn=100233,base=1e9+9; int lc[maxn],rc[maxn],val[maxn],rnd[maxn],tot; ull pre[maxn],jc[maxn]; int s[maxn],sa[maxn],rk[maxn]; int i,j,k,n,m,AFT,PRE,V,rt; ll ans; int ra;char rx; inline int read(){ rx=getchar(),ra=0; while(rx<'0'||rx>'9')rx=getchar(); while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra; } inline int getlcp(int a,int b){ if(s[a]!=s[b])return 0; if(a>b)swap(a,b); int r=n-b+1; a--,b--; if(pre -pre[b]*jc[r]==pre[a+r]-pre[a]*jc[r])return r; int l=1,mid; while(l<r) if(pre[b+(mid=l+r+1>>1)]-pre[b]*jc[mid]==pre[a+mid]-pre[a]*jc[mid]) l=mid;else r=mid-1; return l; } inline bool cmp(int a,int b){ int lcp=getlcp(a,b); return s[a+lcp]<s[b+lcp]; } inline void getsa(){ int i; for(i=jc[0]=1;i<=n;i++)pre[i]=pre[i-1]*base+s[i],jc[i]=jc[i-1]*base,sa[i]=i; sort(sa+1,sa+1+n,cmp); for(i=1;i<=n;i++)rk[sa[i]]=i;//,printf(" %d",sa[i]);puts(""); // for(i=1;i<=n;i++)printf(" %d",rk[i]);puts(""); } inline void lturn(int &x){int R=rc[x];rc[x]=lc[R],lc[R]=x,x=R;} inline void rturn(int &x){int L=lc[x];lc[x]=rc[L],rc[L]=x,x=L;} inline void insert(int &x){ if(!x){x=++tot,val[x]=V,rnd[x]=rand()+tot;return;} if(V<val[x]){ insert(lc[x]); if(rnd[lc[x]]<rnd[x])rturn(x); }else{ insert(rc[x]); if(rnd[rc[x]]<rnd[x])lturn(x); } } void getpre(int x){ if(!x)return; if(val[x]<V)PRE=val[x],getpre(rc[x]); else getpre(lc[x]); } void getaft(int x){ if(!x)return; if(val[x]>V)AFT=val[x],getaft(lc[x]); else getaft(rc[x]); } int main(){ n=read(); for(i=n;i;i--)s[i]=read(); // n=1e5; for(i=n;i;i--)s[i]=1; getsa();//return 233; ans=1,V=rk ,insert(rt);printf("%lld\n",ans); for(i=n-1;i;i--){ PRE=AFT=0,V=rk[i],getpre(rt),getaft(rt); // printf("i:%d rk:%d pre:%d aft:%d\n",i,rk[i],PRE,AFT); if(!PRE||!AFT)ans+=n-i+1-getlcp(i,sa[PRE|AFT]); else ans+=n-i+1-max(getlcp(i,sa[PRE]),getlcp(i,sa[AFT])); printf("%lld\n",ans); V=rk[i],insert(rt); }//printf(" %lld\n",ans); return 0; }
View Code
相关文章推荐
- UITableView 关于cell与cell之间的间距
- linux调用.so动态库
- iso
- org.springframework.orm.hibernate3.LocalSessionFactoryBean的疑惑解决办法
- STM32学习笔记之工程模板的建立
- 前端资源收集
- UWP-ListView下模板宽度问题
- 《剑指offer》:[37]如何得到链表环的入口地址
- Spring MVC入门
- 【Unity Shaders】学习笔记——SurfaceShader(三)BasicDiffuse和HalfLambert
- 设计模式-12-享元
- 学习进度条16
- 《30天自制操作系统》学习笔记(三)
- 博客自定义
- MAC下安装mysql
- ASP.NET MVC中的错误处理
- 汇编指令总结
- android中notification的用法(简单易懂用法)
- Java多线程继承Thread类详解第1/2页
- Centos创建和修改用户及密码命令