bzoj 4650: [Noi2016]优秀的拆分
来源:互联网 发布:单页用什么软件有哪些 编辑:程序博客网 时间:2024/05/17 18:25
原来只会两个log平衡树合并。。后来围观claris在uoj群上秒题后会了这道题。
枚举A(B)的长度L,然后枚举i=kL,考虑前缀i,i+L和后缀i+1,i+L+1,求出前缀的lcp和后缀的lcp,然后合法的方案就在一个方案内。差分一下即可。注意要避免重复。
AC代码如下:
#include<iostream>#include<cstdio>#include<cstring>#define N 30005using namespace std;int n,bin[25],lg2[N],q[N],sum[N],num[N]; char s[N];struct saffix{int a[N],sa[N],f[15][N],rnk[N<<1];void getsa(){int i,j,k,cnt;memset(sum,0,sizeof(int)*26); memset(rnk+n+1,0,sizeof(int)*n);for (i=1; i<=n; i++) sum[a[i]]++;for (i=1; i<26; i++) sum[i]+=sum[i-1];for (i=n; i; i--) sa[sum[a[i]]--]=i;for (i=1,cnt=0; i<=n; i++){if (i==1 || a[sa[i]]!=a[sa[i-1]]) cnt++;rnk[sa[i]]=cnt;}for (k=1; cnt<n; k<<=1){for (i=1; i<=k; i++) q[i]=n-k+i;for (i=1,j=k; i<=n; i++) if (sa[i]>k) q[++j]=sa[i]-k;memset(sum,0,sizeof(sum));for (i=1; i<=n; i++) sum[rnk[i]]++;for (i=1; i<=cnt; i++) sum[i]+=sum[i-1];for (i=n; i; i--) sa[sum[rnk[q[i]]]--]=q[i];for (i=1,cnt=0; i<=n; i++){if (i==1 || rnk[sa[i]]!=rnk[sa[i-1]] || rnk[sa[i]+k]!=rnk[sa[i-1]+k]) cnt++;q[sa[i]]=cnt;}for (i=1; i<=n; i++) rnk[i]=q[i];}}void getf(){int i,j,k;for (i=1,k=0; i<=n; i++){if (k) k--;j=sa[rnk[i]-1];while (i+k<=n && j+k<=n && a[i+k]==a[j+k]) k++;f[0][rnk[i]]=k;}}int lcp(int x,int y){if (y>n) return 0;x=rnk[x]; y=rnk[y]; if (x>y) swap(x,y);int k=lg2[y-x];return min(f[k][x+1],f[k][y-bin[k]+1]);}void pwk(){int i,j;for (i=1; i<=n; i++) a[i]=s[i]-'a';getsa(); getf();for (i=1; i<=14; i++)for (j=1; j<=n; j++){f[i][j]=f[i-1][j];if (j+bin[i-1]<=n) f[i][j]=min(f[i][j],f[i-1][j+bin[i-1]]);}}}ta,tb;int main(){int cas,i; scanf("%d",&cas);bin[0]=1;for (i=1; i<=14; i++){ bin[i]=bin[i-1]<<1; lg2[bin[i]]=i; }for (i=2; i<=30000; i++) if (!lg2[i]) lg2[i]=lg2[i-1];while (cas--){scanf("%s",s+1); n=strlen(s+1);int j,x,y;ta.pwk();for (i=1; i<=(n>>1); i++) swap(s[i],s[n-i+1]);tb.pwk();memset(sum,0,sizeof(sum)); memset(num,0,sizeof(num));for (i=1; i<(n>>1); i++)for (j=i; j+i<=n; j+=i){x=max(j-i+1,j-tb.lcp(n-j+1,n-j-i+1)+1); y=min(j,j-i+1+ta.lcp(j+1,j+i+1));if ((x==10 || y==10) && i==2){}if (x<=y){sum[x]++; sum[y+1]--;num[x+(i<<1)]++; num[y+(i<<1)+1]--;}}long long ans=0;for (i=2; i<=n; i++){sum[i]+=sum[i-1]; num[i]+=num[i-1];ans+=sum[i]*num[i];}printf("%lld\n",ans);}return 0;}
by lych
2016.8.4
0 0
- bzoj 4650: [Noi2016]优秀的拆分
- BZOJ 4650([Noi2016]优秀的拆分-SA)
- BZOJ 4650: [Noi2016]优秀的拆分 哈希+分块
- 4650: [Noi2016]优秀的拆分
- 【NOI2016】优秀的拆分
- [后缀数组 枚举 字符串分段] BZOJ 4650 [Noi2016]优秀的拆分
- bzoj4650: [Noi2016]优秀的拆分
- 【后缀数组】[NOI2016]优秀的拆分
- NOI2016 优秀的拆分 后缀数组
- NOI2016 优秀的拆分 后缀数组
- NOI2016优秀的拆分 后缀数组
- [BZOJ4650][NOI2016]优秀的拆分-后缀数组
- 【NOI2016】优秀的拆分(95分)
- [UOJ P219][NOI2016]优秀的拆分[95]
- [后缀数组] BZOJ4650: [Noi2016] 优秀的拆分
- Noi2016 D1 T1 优秀的拆分 90做法
- UOJ #219 [NOI2016 D1T1] 优秀的拆分 [95分]
- [BZOJ4650][NOI2016]优秀的拆分 各数据点解法
- 各硬件设备在Linux中的文件名、磁盘分区
- js分页
- Java————String类型详解
- PHPDocument 代码注释规范总结
- Android常用工具
- bzoj 4650: [Noi2016]优秀的拆分
- Hdu 5793 A Boring Question【暴力打表+找规律+求逆元+快速幂+快速积】
- NKOI 1939 魔术球
- 8-4日素数的写法
- 精算精确时间
- 反编译字节码
- C++ hdoj 2015 偶数求和
- (NYoj 269) VF --经典DP问题--下一个状态为前多个状态之和
- 友盟登录、分享 注意事项(5.0之前)