博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[NOI 2016] 优秀的拆分
阅读量:5337 次
发布时间:2019-06-15

本文共 3465 字,大约阅读时间需要 11 分钟。

题意:

\(T\)组数据,对于每组数据:

给你一个长度为\(n\)的字符串\(S\)
定义一个字符串\(t\)是好的,当且仅当它能被表示成\(aabb\)的形式,其中a和b都是字符串(可以相同)
\(S\)中有多少个子串是好的(本质相同位置不同也算不同)
\(T \le 10,n \le 30000\)

题解:

这题的构造方法极其巧妙,是道好题。

我们可以维护两个数组分别表示某个位置为结尾/开头的aa型字符串有多少个
那显然\(ans=\sum_{i=1}^{n-1}f_{i}*g_{i+1}\)(大概意思一下)
那考虑如何统计\(f\)\(g\)
我们枚举\(a\)的长度\(len\),并设置\(len,2*len,...,\lfloor \frac{n}{len}\rfloor *len\)为关键点,求出相邻关键点的\(LCP\)\(LCS\)(最长公共前/后缀),大概画幅图就知道对那些点有贡献,差分一下就可以得到\(f\)\(g\)了。

过程:

犯了个严重错误:见LCA中的第1点

同时写代码的时候在变量代表的意义上纠结不清导致调题过程过长

代码:

const int N=30010;int n;char S[N];int valf[N],valb[N];//i as end/startint s_t[2][N<<2],t_s[2][N<<1],dep[2][N<<1],fa[2][N<<1],cur=0;int head[N<<1],nxt[N<<1],to[N<<1],lst=0;int NOW,ref[2][N];inline void adde(int x,int y) {    nxt[++lst]=head[x]; to[lst]=y; head[x]=lst;}namespace SAM {    const int U=26;    struct NODE {        int tranc[U],dep,fa;    }tre[N<<1];    int las,rt,ind;    inline int New_Node() {        ++ind; mem(tre[ind].tranc,0); tre[ind].dep=tre[ind].fa=0;        return ind;    }    inline void Init() {        mem(tre,0);        cur=lst=0; mem(head,0);        ind=0; las=rt=New_Node();    }    inline void Insert(int x) {        // printf("test:%d\n",tre[1].tranc[1]);        int p=las,np=New_Node(); tre[np].dep=tre[p].dep+1;        for(;p && !tre[p].tranc[x];p=tre[p].fa) tre[p].tranc[x]=np;        if(!p) {tre[np].fa=rt;}        else {            int q=tre[p].tranc[x];            if(tre[p].dep+1==tre[q].dep) {tre[np].fa=q;}            else {                int nq=New_Node(); tre[nq].dep=tre[p].dep+1;                memcpy(tre[nq].tranc,tre[q].tranc,sizeof(tre[q].tranc));                tre[nq].fa=tre[q].fa; tre[q].fa=tre[np].fa=nq;                for(;p && tre[p].tranc[x]==q;p=tre[p].fa) tre[p].tranc[x]=nq;            }        }        las=np;    }    inline void Build() {        for(int i=1;i<=ind;i++)            if(tre[i].fa) adde(tre[i].fa,i);    }    void dfs(int u) {        // printf("u=%d dep=%d\n",u,tre[u].dep);        dep[NOW][u]=tre[u].dep; fa[NOW][u]=tre[u].fa;        s_t[NOW][++cur]=u; t_s[NOW][u]=cur;        for(int i=head[u];i;i=nxt[i]) {            int v=to[i];            if(v) {                dfs(v);                s_t[NOW][++cur]=u;            }        }    }}inline void Get_SAM(char *s) {    if(NOW) reverse(s+1,s+n+1);    for(int i=1;i<=n;i++) {        SAM::Insert(s[i]-'a');        ref[NOW][NOW ? n-i+1 : i]=SAM::las;    }    SAM::Build(); SAM::dfs(SAM::rt);}namespace ST {    const int lgN=18;    int st[2][N<<2][lgN+3],lg[N<<2];    inline void Set() {        lg[1]=0;        for(int i=2;i<=120000;i++)            lg[i]=lg[i>>1]+1;    }    inline void Init() {        mem(st,63);    }    inline int Comp(int x,int y,int c) {return dep[c][x]
y) swap(x,y); // if(x>y) swap(x,y); int tmp=lg[y-x+1]; // printf("%d %d %d\n",x,y,tmp); // printf("ask::%d\n",fa[c][Comp(st[c][x][tmp],st[c][y-(1<
=len-1) { int s=max(st,st+len-lcs),t=min(st+len-1,st+lcp-1);//s=st+len-1-lcs+1 // printf("%d %d\n",s,t); // printf("%d %d %d\n",len,s+len,t+len+1); ++valf[s+len]; --valf[t+len+1]; // printf("%d %d %d\n",len,s-len,t-len+1); ++valb[s-len+1]; --valb[t-len+2]; } } } for(int i=1;i<=n;i++) valf[i]+=valf[i-1]; for(int i=1;i<=n;i++) valb[i]+=valb[i-1]; ll ans=0; for(int i=2;i

用时:3h

转载于:https://www.cnblogs.com/functionendless/p/9562710.html

你可能感兴趣的文章
常用的107条Javascript
查看>>
#10015 灯泡(无向图连通性+二分)
查看>>
忘记root密码,怎么办
查看>>
linux设备驱动归纳总结(三):1.字符型设备之设备申请【转】
查看>>
《黑客与画家》 读书笔记
查看>>
bzoj4407: 于神之怒加强版
查看>>
mysql统计一张表中条目个数的方法
查看>>
ArcGIS多面体(multipatch)解析——引
查看>>
css3渐变画斜线 demo
查看>>
JS性能DOM优化
查看>>
设计模式 单例模式 使用模板及智能指针
查看>>
c#的const可以用于引用类型吗
查看>>
手动实现二值化
查看>>
What Linux bind mounts are really doing
查看>>
linux top命令详解
查看>>
博弈论小结
查看>>
模拟Post登陆带验证码的网站
查看>>
NYOJ458 - 小光棍数
查看>>
java中常用方法
查看>>
【Programming Clip】06、07年清华计算机考研上机试题解答(个别测试用例无法通过)...
查看>>