题面

其实题目不算很难,但是我调试的时候被玄学了,for循环里不写空格会RE,写了才能过。神**调了一个多小时是这么个不知道是什么的玩意(真事,可以问i207M=。=),心态爆炸

发现我们只要找AA或者BB就行了,因为另一半反过来再做一次然后拼起来就可以了,那么就设$stp[i]$表示从$i$开始有多少个$AA$这样的串,$edp[i]$表示在$i$结束有多少个$AA$这样的串。一个个位置暴力求是$O(n^2)$的,可以得95pts(雾。

AC做法是一种巧妙(套路?毕竟我做题少)的做法。枚举一个len把串分成长度为$len$的段,然后发现形如$AA$的字符串一定至少跨过了两个分界点,那么我们求一下这两个分界点的$LCP$和$LCS$,看看是不是超过$len$即可,然后具体的贡献可以用差分实现,时间复杂度$O(n\log n)$(不知道为啥$n$只出了30000,可能是为了放哈希+二分的$O(n\log^2 n)$过去?)。

  1 #include<cmath>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 using namespace std;
  6 const int N=30005,K=16;
  7 struct a
  8 {
  9     char str[N];
 10     int sec[N],bkt[N];
 11     int sar[N],rnk[N],hgt[N],st[N][K];
 12     int len,siz;
 13     void Set()
 14     {
 15         len=0,siz=30;
 16         memset(sec,0,sizeof sec);
 17         memset(rnk,0,sizeof rnk);
 18     }
 19     void Prework()
 20     {
 21         register int i;
 22         for(i=1;i<=len;i++)
 23             rnk[i]=str[i]-'a'+1,sec[i]=i;
 24     }
 25     void Basenum_Sort()
 26     {
 27         register int i;
 28         for(i=1;i<=siz;++i) bkt[i]=0;
 29         for(i=1;i<=len;++i) ++bkt[rnk[i]];
 30         for(i=1;i<=siz;++i) bkt[i]+=bkt[i-1];
 31         for(i=len;i>=1;--i) sar[bkt[rnk[sec[i]]]--]=sec[i];
 32     }
 33     void Suffix_Sort()
 34     {
 35         register int i;
 36         int cnt=0,pw=1;
 37         Basenum_Sort();
 38         while(cnt<len)
 39         {
 40             cnt=0;
 41             for(i=1;i<=pw;i++) sec[++cnt]=len-pw+i;
 42             for(i=1;i<=len;i++) if(sar[i]>pw) sec[++cnt]=sar[i]-pw;
 43             Basenum_Sort(); swap(rnk,sec); rnk[sar[1]]=cnt=1;
 44             for(i=2;i<=len;i++)
 45                 cnt+=(sec[sar[i-1]]!=sec[sar[i]]||sec[sar[i-1]+pw]!=sec[sar[i]+pw]),rnk[sar[i]]=cnt;
 46             pw<<=1,siz=cnt;
 47         }
 48     }
 49     void Getting_Height()
 50     {
 51         register int i,p=0;
 52         for(i=1;i<=len;i++)
 53             if(rnk[i]!=1)
 54             {
 55                 int r=sar[rnk[i]-1];
 56                 while(str[r+p]==str[i+p]) p++;
 57                 hgt[rnk[i]]=p; if(p>0) p--;
 58             }
 59         hgt[1]=0;
 60     }
 61     void Building_Table()
 62     {
 63         register int i,j;
 64         for(i=1;i<=len;i++)
 65             st[i][0]=hgt[i];
 66         int lgg=log2(len);
 67         for(i=1;i<=lgg;i++)
 68             for(j=1;j<=len-(1<<i)+1;j++)
 69                 st[j][i]=min(st[j][i-1],st[j+(1<<(i-1))][i-1]);
 70     }
 71     int LCP_Query(int x,int y)
 72     {
 73         int xx=rnk[x],yy=rnk[y],lgg;
 74         if(xx>yy) swap(xx,yy); xx++,lgg=log2(yy-xx+1);
 75         return min(st[xx][lgg],st[yy-(1<<lgg)+1][lgg]);
 76     }
 77 }SA[2];
 78 int n,lth,stp[N],edp[N];
 79 void Init()
 80 {
 81     SA[0].Set(),SA[1].Set();
 82     memset(stp,0,sizeof stp);
 83     memset(edp,0,sizeof edp);
 84 }
 85 int main()
 86 {
 87     register int i,j,k,h;
 88     scanf("%d",&n);
 89     for(i=1;i<=n;i++)
 90     {
 91         Init(); scanf("%s",SA[0].str+1);
 92         SA[0].len=SA[1].len=lth=strlen(SA[0].str+1);
 93         for(j=1;j<=lth;j++)
 94             SA[1].str[j]=SA[0].str[lth-j+1];
 95         for(j=0;j<=1;j++)
 96         {
 97             SA[j].Prework();
 98             SA[j].Suffix_Sort();
 99             SA[j].Getting_Height();
100             SA[j].Building_Table();
101         }
102         for(j=1;j<=lth/2;j++)
103         {
104             for(k=j,h=2*j;h<=lth;k+=j,h+=j)
105             {
106                 int l1=min(SA[0].LCP_Query(k,h),j);
107                 int l2=min(SA[1].LCP_Query(lth-k+1,lth-h+1),j);
108                 if(l1+l2>j)
109                 {
110                     stp[k-l2+1]++,edp[h-l2+j]++;
111                     stp[k+l1-j+1]--,edp[h+l1]--;
112                 }
113             }
114         }
115         long long ans=0;
116         for(j=1;j<=lth;j++)
117             stp[j]+=stp[j-1],edp[j]+=edp[j-1];
118         for(j=1;j<lth;j++)
119             ans+=1ll*stp[j+1]*edp[j];
120         printf("%lld\n",ans);
121     }
122     return 0;
123 }

View Code

Upd on 2019.3.16:用SAM搞过去了,然而因为常数原因被同样复杂度的SA踩了

你问怎么做到同样复杂度?写个RMQ LCA就行了(我就因为写这个才学的RMQ LCA=。=)

  1 #include<cmath>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 using namespace std;
  6 const int N=60005,K=17;
  7 struct SAM
  8 {
  9     char str[N];
 10     int p[N],noww[N],goal[N];
 11     int dfn[N],idf[N],fir[2*N],st[N][K];
 12     int trs[N][26],fth[N],len[N],ndp[N];
 13     int lth,lst,tot,cnt,dfo,app;
 14     void Init()
 15     {
 16         cnt=dfo=app=0,tot=lst=1;
 17         memset(p,0,sizeof p);
 18         memset(fth,0,sizeof fth);
 19         memset(len,0,sizeof len);
 20         memset(trs,0,sizeof trs);
 21     }
 22     void Link(int f,int t)
 23     {
 24         noww[++cnt]=p[f];
 25         goal[cnt]=t,p[f]=cnt;
 26     }
 27     int Insert(int ch)
 28     {
 29         int nde=lst,newn=++tot;
 30         lst=newn,len[newn]=len[nde]+1;
 31         while(nde&&!trs[nde][ch])
 32             trs[nde][ch]=newn,nde=fth[nde];
 33         if(!nde) fth[newn]=1;
 34         else
 35         {
 36             int tran=trs[nde][ch];
 37             if(len[tran]==len[nde]+1)
 38                 fth[newn]=tran;
 39             else
 40             {
 41                 int rnde=++tot; len[rnde]=len[nde]+1;
 42                 for(int i=0;i<=25;i++) trs[rnde][i]=trs[tran][i];
 43                 fth[rnde]=fth[tran],fth[tran]=fth[newn]=rnde;
 44                 while(nde&&trs[nde][ch]==tran)
 45                     trs[nde][ch]=rnde,nde=fth[nde];
 46             }
 47         }
 48         return newn;
 49     }
 50     void DFS(int nde)
 51     {
 52         idf[dfn[nde]=++dfo]=nde;
 53         st[fir[nde]=++app][0]=dfo;
 54         for(int i=p[nde];i;i=noww[i])
 55             DFS(goal[i]),st[++app][0]=dfn[nde];
 56     }
 57     int LCA(int x,int y)
 58     {
 59         x=fir[x],y=fir[y];
 60         if(x>y) swap(x,y);
 61         int l2=log2(y-x+1);
 62         return idf[min(st[x][l2],st[y-(1<<l2)+1][l2])];
 63     }
 64     void Create()
 65     {
 66         for(int i=1;i<=lth;i++)
 67             ndp[i]=Insert(str[i]-'a');
 68         for(int i=1;i<=tot;i++)
 69             Link(fth[i],i); DFS(1);
 70         for(int i=1;i<=16;i++)
 71             for(int j=1;j+(1<<i)-1<=app;j++)
 72                 st[j][i]=min(st[j][i-1],st[j+(1<<(i-1))][i-1]);
 73     }
 74     int LCS(int x,int y)
 75     {
 76         int lca=LCA(ndp[x],ndp[y]);
 77         return len[lca];
 78     }
 79 }s[2];
 80 int n,m,stp[N],edp[N];
 81 void Init()
 82 {
 83     memset(stp,0,sizeof stp);
 84     memset(edp,0,sizeof edp);
 85 }
 86 int main()
 87 {
 88     register int i,j,k,h;
 89     scanf("%d",&n);
 90     for(i=1;i<=n;i++)
 91     {
 92         Init(); scanf("%s",s[0].str+1);
 93         s[0].lth=s[1].lth=m=strlen(s[0].str+1);
 94         for(j=1;j<=m;j++) s[1].str[j]=s[0].str[m-j+1];
 95         s[0].Init(),s[0].Create();
 96         s[1].Init(),s[1].Create();
 97         for(j=1;j<=(m>>1);j++)
 98         {
 99             for(k=j,h=2*j;h<=m;k+=j,h+=j)
100             {
101                 int l1=min(s[0].LCS(k,h),j);
102                 int l2=min(s[1].LCS(m-k+1,m-h+1),j);
103                 if(l1+l2>j)
104                 {
105                     stp[k-l1+1]++,edp[h-l1+j]++;
106                     stp[k+l2-j+1]--,edp[h+l2]--;
107                 }
108             }
109         }
110         long long ans=0;
111         for(j=1;j<=m;j++) stp[j]+=stp[j-1],edp[j]+=edp[j-1];
112         for(j=1;j<m;j++) ans+=1ll*stp[j+1]*edp[j];
113         printf("%lld\n",ans);
114     }
115     return 0;
116 }

View Code

转载于:https://www.cnblogs.com/ydnhaha/p/10148244.html

解题:NOI 2016 优秀的拆分相关推荐

  1. NOI 2016 优秀的拆分 (后缀数组+差分)

    题目大意:给你一个字符串,求所有子串的所有优秀拆分总和,优秀的拆分被定义为一个字符串可以被拆分成4个子串,形如$AABB$,其中$AA$相同,$BB$相同,$AB$也可以相同 作为一道国赛题,95分竟 ...

  2. UOJ #219 BZOJ 4650 luogu P1117 [NOI2016]优秀的拆分 (后缀数组、ST表)

    UOJ #219 BZOJ 4650 luogu P1117 [NOI2016]优秀的拆分 (后缀数组.ST表) 连NOI Day1T1都不会做...看了题解都写不出来还要抄Claris的代码.. 题 ...

  3. 信息学奥赛一本通 2004:【20CSPJ普及组】优秀的拆分 | 洛谷 P7071 [CSP-J2020] 优秀的拆分

    [题目链接] ybt 2004:[20CSPJ普及组]优秀的拆分 洛谷 P7071 [CSP-J2020] 优秀的拆分 [题目考点] 数制 基数:即进制数.十进制的基数是10,二进制的基数是2. 按位 ...

  4. [BZOJ]4650 优秀的拆分(Noi2016)

    比较有意思的一道后缀数组题.(小C最近是和后缀数组淦上了?) 放在NOI的考场上.O(n^3)暴力80分,O(n^2)暴力95分-- 即使想把它作为一道签到题也不要这么随便啊摔(╯‵□′)╯︵┻━┻ ...

  5. 基础算法4 —— 结构体(成绩统计) + 栈(模拟进制转换 + 优秀的拆分) + 指针

    结构体 结构体的实际应用场景: 在实际问题中,一组数据往往具有不同的数据类型.比如,某次期末考试中要记录一个学生的考试信息,除了有姓名(char)外,还有班级(int).性别(char).语文.数学. ...

  6. 【NOI2016】优秀的拆分(后缀数组)

    题目描述 如果一个字符串可以被拆分为AABBAABB的形式,其中 A和 B是任意非空字符串,则我们称该字符串的这种拆分是优秀的. 例如,对于字符串aabaabaa,如果令 A=aab,B=a,我们就找 ...

  7. CSP - J 2020 T1 优秀的拆分

    https://www.luogu.com.cn/problem/P7071 /* CSP - J 2020 T1 优秀的拆分 https://www.luogu.com.cn/problem/P70 ...

  8. P1117 [NOI2016]优秀的拆分

    $ \color{#0066ff}{ 题目描述 }$ 如果一个字符串可以被拆分为\(AABB\)的形式,其中 A和 B是任意非空字符串,则我们称该字符串的这种拆分是优秀的. 例如,对于字符串\(aab ...

  9. [NOI2016] 优秀的拆分 题解

    [NOI2016] 优秀的拆分 题解 link 题意 \(T\) 组询问,每组一个字符串 \(s\) 求 \(s\) 所有字串分成 \(AABB\) 的方案数之和. \(A,B\) 为非空串. 题解 ...

  10. NOI2016 优秀的拆分(图解)

    如果一个字符串可以被拆分为 AABB 的形式,其中 A和 B是任意非空字符串,则我们称该字符串的这种拆分是优秀的. 例如,对于字符串 aabaabaa,如果令 A=aab,B=a,我们就找到了这个字符 ...

最新文章

  1. java定时关机源码_java实现电脑定时关机的方法
  2. 产品经理如何评估产品机会
  3. linux 报错 E: 无法定位软件包 python-lzma
  4. stateflow中终止节点小记
  5. glid加载不出来图片
  6. 2018年澳门就业情况理想 最新失业率维持1.7%
  7. [MySQL FAQ]系列 -- 如何直接覆盖 MYI MYD 文件
  8. 学习 Kotlin 的 20 个实用资源
  9. 小米小爱音箱Pro8安装app_小米小爱音箱HD:声与色的美
  10. SQL语句批量替换某个指定的字符串
  11. SI4463配置软件wds3
  12. 代码没问题但运行不出来
  13. ArcGIS 10安装方法(对比流行的2种安装方法)||迅雷电驴下载地址
  14. 计算机工程中级职称怎么考,以前中级职称是要考什么计算机-计算机软考中级职称哪个好考...
  15. cyberduck 源代码学习记录一,编译源代码 build for window
  16. vscode 插件推荐 - 献给所有前端工程师
  17. 种类并查集(POJ1703)
  18. 苹果选了天猫 天猫成了618
  19. 古文字识别助手与众包平台——项目博客二
  20. IT增值服务客户案例(二):河南郑州大四实习生,职业规划和项目开发指导

热门文章

  1. 我经常逛的技术网站,个个经典
  2. Android 下拉刷新库,这一个就够了!
  3. 三包围结构的字是什么样的_清桦学书之结构篇——包围结构。
  4. 字符串的模板 Manacher kmp ac自动机 后缀数组 后缀自动机
  5. 由swap引出的局部变量,形参和指针的小问题
  6. C++请不要问我string s=”a”+”b”分配了几次内存
  7. django 静态文件的配置 orm 中 字段与数据的增删改查 使用MySQL数据库
  8. SonarLint各种提示的意思
  9. 使用 Sixel 图形格式在终端中显示缩略图
  10. 自定义函数hello,并注册到hive源码中并重新编译