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

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

作为一道国赛题,95分竟然就这么给我们了!只是一个$NOIP$难度的哈希套$DP$啊......

95分就是从后往前找,统计$AA$串,每次统计一下从这个位置开始的所有子串 和 紧随其后的等长串 相同的个数$sum$

$hash(i,i+j-1)==hash(i+j,i+2*j-1) sum[i]++$

然后再统计$BB$串,就是加上在这两个串之后的位置的$sum$值,这样就统计出了合法拆分数

$dp[i]+=sum[i+2*j]$

95分就这样到手啦,竟然连自然溢出hash都不卡

 1 #include <cmath>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #define ll long long 
 6 #define ull unsigned long long 
 7 #define N 2050
 8 #define seed 233
 9 #define idx(x) (x-'a'+1)
10 using namespace std;
11 //re
12 int T,len;
13 char str[N];
14 int dp[N],sum[N];
15 ull hsh[N],sp[N];
16 ull ghsh(int x,int y) {return hsh[y]-hsh[x-1]*sp[y-x+1];}
17 void clr()
18 {
19     memset(dp,0,sizeof(dp));
20     memset(sp,0,sizeof(sp));
21     memset(sum,0,sizeof(sum));
22     memset(hsh,0,sizeof(hsh));
23 }
24 int main()
25 {
26     scanf("%d",&T);
27     while(T--)
28     {
29         clr();
30         scanf("%s",str+1);
31         len=strlen(str+1);
32         sp[0]=1;
33         for(int i=1;i<=len;i++)
34             hsh[i]=hsh[i-1]*seed+idx(str[i]),
35             sp[i]=sp[i-1]*seed;
36         for(int i=len-1;i>=1;i--)
37         {
38             for(int j=1;i+2*j-1<=len;j++)
39             {
40                 if(ghsh(i,i+j-1)==ghsh(i+j,i+2*j-1)){
41                     dp[i]++;
42                     sum[i]+=dp[i+2*j];
43                 }
44             }
45         }
46         int ans=0;
47         for(int i=1;i<=len;i++)
48             ans+=sum[i];
49         printf("%d\n",ans);
50     }
51     return 0;
52 }

接下来才是本题的重点!$NOI$岂是你想$AK$就$AK$的!出题人可能是想针对某位巨佬

不看题解这个正解思路真是很难想到......

思路大概是这样的,其实我们每次只需要统计$AA$串的数量就行了,因为$AABB$串的数量等于,在$i-1$位结束的$AA$串的数量乘以在第$i$位开始的$AA$串的数量,用公式表示就是

\sum_{i=2}^{n} ed[i-1]*st[i]

接下来就是统计$st$和$ed$了,感觉正解的思路很神

先用后缀数组+$ST$表处理出任意两个位置,作为后缀串开头的$LCP$以及作为前缀串末尾的$LCS$,求$LCS$可以把串反着读再去套$SA$

每次选取一个$A$串的长度$len$,再在原串每隔$len$的位置设一个关键点

然后会发现一个神奇的性质,任意一个长度为$2*len$的串必然经过且仅经过2个关键点!

接下来统计经过所有长度为$2*len$所有$AA$串,比如选定两个关键点$a,b$,且$a+len=b$

如果把$a$的和b$相同的前缀和后缀拼在一起,且拼完之后长度>=len,说明存在至少一个$AA$串

可以把$AA$串想象成一个块,在两个关键点上移动,块的左端点不能大于$a$,块的右端点不能小于$b$,块不能移动到上一个或者下一个关键点的位置,块内必须是$AA$串,这样,块所有能移动的位置-块的长度$len$,就是经过$ab$两个关键点的所有$AA$串数

时间变成O(nlogn),$logn$是调和级数的近似值

细节比较多需要仔细思考

  1 #include <cmath>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #define ll long long 
  6 #define N 30100
  7 #define seed 233
  8 #define idx(x) (x-'a'+1)
  9 using namespace std;
 10 //re
 11 int T,len;
 12 int lg[N];
 13 ll st[N],ed[N],S[N],E[N];
 14 struct suffix{
 15     char str[N];
 16     int sa[N],tr[N],rk[N],hs[N],h[N],f[N][15],len; 
 17     bool check(int k,int x,int y){
 18         if(x+k>len||y+k>len) return 0;
 19         else return (rk[x]==rk[y]&&rk[x+k]==rk[y+k])?1:0;
 20     }
 21     void get_suffix()
 22     {
 23         int cnt=0,i;len=strlen(str+1);
 24         for(i=1;i<=len;i++) hs[str[i]]++;
 25         for(i=1;i<=127;i++) if(hs[i]) tr[i]=++cnt;
 26         for(i=1;i<=127;i++) hs[i]+=hs[i-1];
 27         for(i=1;i<=len;i++) rk[i]=tr[str[i]],sa[hs[str[i]]--]=i;
 28         for(int k=1;cnt<len;k<<=1)
 29         {
 30             for(i=1;i<=cnt;i++) hs[i]=0;
 31             for(i=1;i<=len;i++) hs[rk[i]]++;
 32             for(i=1;i<=cnt;i++) hs[i]+=hs[i-1];
 33             for(i=len;i>=1;i--) if(sa[i]>k) tr[sa[i]-k]=hs[rk[sa[i]-k]]--;
 34             for(i=1;i<=k;i++) tr[len-i+1]=hs[rk[len-i+1]]--;
 35             for(i=1;i<=len;i++) sa[tr[i]]=i;
 36             for(i=1,cnt=0;i<=len;i++) tr[sa[i]]=check(k,sa[i],sa[i-1])?cnt:++cnt;
 37             for(i=1;i<=len;i++) rk[i]=tr[i];
 38         }
 39         for(i=1;i<=len;i++)
 40         {
 41             if(rk[i]==1) continue;
 42             for(int j=max(1,h[rk[i-1]]-1);;j++)
 43                 if(str[i+j-1]==str[sa[rk[i]-1]+j-1]) h[rk[i]]=j;
 44                 else break;
 45         }
 46     }
 47     void get_ST()
 48     {
 49         for(int i=1;i<=len;i++) 
 50             f[i][0]=h[i];
 51         for(int k=1;(1<<k)<=len;k++)
 52             for(int i=1;i+(1<<k)-1<=len;i++)
 53                 f[i][k]=min(f[i][k-1],f[i+(1<<(k-1))][k-1]);
 54     }
 55     int query(int x,int y)
 56         {int L=y-x+1;
 57         return min(f[x][lg[L]],f[y-(1<<lg[L])+1][lg[L]]);}
 58 }p,s;
 59 void clr()
 60 {
 61     memset(S,0,sizeof(S)),memset(st,0,sizeof(st));
 62     memset(E,0,sizeof(E)),memset(ed,0,sizeof(ed));
 63     memset(&p,0,sizeof(p)),memset(&s,0,sizeof(s));
 64 }
 65 int main()
 66 {
 67     scanf("%d",&T);
 68     for(int i=2;i<=30010;i++)
 69         lg[i]=lg[i>>1]+1;
 70     while(T--)
 71     {
 72         clr();
 73         scanf("%s",s.str+1);
 74         int len=strlen(s.str+1);
 75         for(int i=1;i<=len;i++) 
 76             p.str[i]=s.str[len-i+1];
 77         s.get_suffix();
 78         s.get_ST();
 79         p.get_suffix();
 80         p.get_ST();
 81         int sx,sy,px,py,ss,sp,l,r;
 82         for(int i=1;i<=len;i++)
 83         {
 84             for(int j=i+1;j<=len;j+=i)
 85             {
 86                 sx=s.rk[j-i+1],sy=s.rk[j+1];
 87                 if(sx>sy) swap(sx,sy);
 88                 px=p.rk[len-(j-i)+1],py=p.rk[len-j+1];
 89                 if(px>py) swap(px,py);
 90                 ss=s.query(sx+1,sy);
 91                 sp=p.query(px+1,py);
 92                 if(ss+sp<i||sp==0) continue;
 93                 l=max(j-i-i+1,j-i-sp+1);
 94                 r=min(j+i-1,j+ss);
 95                 S[l]++,S[r-2*i+2]--;
 96                 E[l+2*i-1]++,E[r+1]--;
 97             }
 98         }
 99         for(int i=1;i<=len;i++)
100             st[i]=st[i-1]+S[i],ed[i]=ed[i-1]+E[i];
101         ll ans=0;
102         for(int i=2;i<=len;i++)
103             ans+=ed[i-1]*st[i];
104         printf("%lld\n",ans);
105     }
106     return 0;
107 }

 

转载于:https://www.cnblogs.com/guapisolo/p/9707026.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/388412.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

多元线性回归 python_Python中的多元线性回归

多元线性回归 pythonVideo Link影片连结 This episode expands on Implementing Simple Linear Regression In Python. We extend our simple linear regression model to include more variables.本集扩展了在Python中实现简单线性回归的方法 。 我们扩展了简单的线性回归模型…

关于apache和tomcat集群,线程是否占用实验

测试目的&#xff1a; 测试在apache入口的时候进入&#xff0c;当Tomcat的一个请求陷入死循环&#xff0c;或者线程进入循环无反应的时候&#xff0c;是否此时占用apache的线程资源。 测试原因&#xff1a; 如果要是影响&#xff0c;无论tomcat线程设置成多大&#xff0c;都…

爬虫之数据解析的三种方式

一&#xff0c;正则表达式解析 re正则就不写了&#xff0c;前面已经写入一篇很详细的正则表达式模块了~ 而且&#xff0c;在爬虫中&#xff0c;下面两种方式用的多一些~ 正则表达式&#xff1a;https://www.cnblogs.com/peng104/p/9619801.html 大致用法&#xff1a; pattern …

相对于硬件计算机软件就是,计算机的软件是将解决问题的方法,软件是相对于硬件来说的...

计算机网络管理软件是为计算机网络配置的系统软件。它负责对网络资源进行组织和管理&#xff0c;实现相互之间的通信。计算机网络管理软件包括网络操作系统和数据通信处理程序。前者用于协调网络中各计算机的操作系统及实现网络资源的传递&#xff0c;后者用于网络内的通信&…

数据冒险控制冒险_劳动生产率和其他冒险

数据冒险控制冒险Labor productivity is considered one of the most important indicators of a country’s well-being. However, we don’t know so much about it, let’s try to figure out how it is calculated, and how things are with it in the world (data source:…

如何把一个java程序打包成exe文件,运行在没有java虚

如何把一个java程序打包成exe文件&#xff0c;运行在没有java虚 核心提示&#xff1a;首先&#xff0c;将编译好的程序打包成jar文件&#xff0c;然后做出exe&#xff0c;这样代码就不可见了&#xff1b;但是exe文件在没有安装jre的电脑上不能运行&#xff0c;如果要求客户再去…

Java后端WebSocket的Tomcat实现

原文&#xff1a;https://www.cnblogs.com/xdp-gacl/p/5193279.html 一.WebSocket简单介绍 随着互联网的发展&#xff0c;传统的HTTP协议已经很难满足Web应用日益复杂的需求了。近年来&#xff0c;随着HTML5的诞生&#xff0c;WebSocket协议被提出&#xff0c;它实现了浏览器与…

加速业务交付,从 GKE 上使用 Kubernetes 和 Istio 开始

原文来源于&#xff1a;谷歌云技术博客 许多企业机构正在把全部或部分 IT 业务迁移到云端&#xff0c;帮助企业更好的运营。不过这样的大规模迁移&#xff0c;在企业的实际操作中也有一定难度。不少企业保存在本地服务器的重要资源&#xff0c;并不支持直接迁移到云端。 另外&a…

knn 邻居数量k的选取_选择K个最近的邻居

knn 邻居数量k的选取Classification is more-or-less just a matter of figuring out to what available group something belongs.分类或多或少只是弄清楚某个事物所属的可用组的问题。 Is Old Town Road a rap song or a country song?Old Town Road是说唱歌曲还是乡村歌曲…

计算机网络中 子网掩码的算法,[网络天地]子网掩码快速算法(转载)

看到一篇很好的资料&#xff0c;大家分享有很多人肯定对设定子网掩码这个不熟悉&#xff0c;很头疼&#xff0c;那么我现在就告诉大家一个很容易算子网掩码的方法&#xff0c;帮助一下喜欢偷懒的人&#xff1a;)大家都应该知道2的0次方到10次方是多少把&#xff1f;也给大家说一…

EXTJS+JSP上传文件带进度条

需求来源是这样的&#xff1a;上传一个很大的excel文件到server&#xff0c; server会解析这个excel&#xff0c; 然后一条一条的插入到数据库&#xff0c;整个过程要耗费很长时间&#xff0c;因此当用户点击上传之后&#xff0c;需要显示一个进度条&#xff0c;并且能够根据后…

android Json详解

Json:一种轻量级的数据交换格式&#xff0c;具有良好的可读和便于快速编写的特性。业内主流技术为其提供了完整的解决方案&#xff08;有点类似于正则表达式 &#xff0c;获得了当今大部分语言的支持&#xff09;&#xff0c;从而可以在不同平台间进行数据交换。JSON采用兼容性…

react实践

React 最佳实践一、 React 与 AJAXReact 只负责处理 View 这一层&#xff0c;它本身不涉及网络请求 /AJAX: 第一&#xff0c;用什么技术从服务端获取数据&#xff1b; 第二&#xff0c;获取到的数据应该放在 react 组件的什么位置。 事实上是有很多的&#xff1a;fetch()、fetc…

什么样的代码是好代码_什么是好代码?

什么样的代码是好代码编码最佳实践 (Coding Best-Practices) In the following section, I will introduce the topic at hand, giving you a sense of what this post will cover, and how each argument therein will be approached. Hopefully, this will help you decide w…

nginx比较apache

话说nginx在大压力的环境中比apache的表现要好&#xff0c;于是下载了一个来折腾一下。 下载并编译安装&#xff0c;我的编译过程有点特别&#xff1a; 1。去除调试信息&#xff0c;修改$nginx_setup_path/auto/cc/gcc这个文件&#xff0c;将 CFLAGS"$CFLAGS -g" …

计算机主板各模块复位,电脑主板复位电路工作原理分析

电源、时钟、复位是主板能正常工作的三大要素。主板在电源、时钟都正常后&#xff0c;复位系统发出复位信号&#xff0c;主板各个部件在收到复位信号后&#xff0c;同步进入初始化状态。如图7-11所示为复位电路的工作原理图&#xff0c;各个十板实现复位的电路不尽相同&#xf…

Docker制作dotnet core控制台程序镜像

(1)首先我们到某个目录下&#xff0c;然后在此目录下打开visual studio code. 2.编辑docker file文件如下: 3.使用dotnet new console创建控制台程序; 4.使用docker build -t daniel/console:dev .来进行打包; 5.启动并运行镜像; 6.我们可以看到打包完的镜像将近2G,因为我们使用…

【362】python 正则表达式

参考&#xff1a;正则表达式 - 廖雪峰 参考&#xff1a;Python3 正则表达式 - 菜鸟教程 参考&#xff1a;正则表达式 - 教程 re.match 尝试从字符串的起始位置匹配一个模式&#xff0c;如果不是起始位置匹配成功的话&#xff0c;match()就返回none。 re.search 扫描整个字符串并…

在Python中使用Twitter Rest API批量搜索和下载推文

数据挖掘 &#xff0c; 编程 (Data Mining, Programming) Getting Twitter data获取Twitter数据 Let’s use the Tweepy package in python instead of handling the Twitter API directly. The two things we will do with the package are, authorize ourselves to use the …

第一套数字电子计算机,计算机试题第一套

《计算机试题第一套》由会员分享&#xff0c;可在线阅读&#xff0c;更多相关《计算机试题第一套(5页珍藏版)》请在人人文库网上搜索。1、计算机试题第一套1、计算机之所以能自动运算,就是由于采用了工作原理。A、布尔逻辑。B 储存程序。C、数字电路。D,集成电路答案选B2、“长…