bzoj 4199: [Noi2015]品酒大会 后缀数组+并查集
2017-04-11 15:23
435 查看
题意
给出一个 长度为 n 的字符串,每一位有一个权值 val。定义两个位字符为 r 相似,是指分别从这两个字符开始,到后面的 r 个字符都相等。两个 r 相似的字符还有一个权值为这两个字符权值的乘积。问对于 r = 0, 1, 2, … , n - 1,统计出有多少种方法可以选出 2 个“r 相似”的字符,并回答选择 2 个”r 相似”的字符可以得到的权值的最大值。n<=3*10^5,val <=10^9
分析
先构造出height数组,然后把height数组从大到小排序,并逐个加入。每加入一个就用并查集维护一下数量,最大值次大值,最小值次小值并计算一波贡献即可。一开始用vector来排序height数组结果T了,改成排序才过。。。
代码
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; typedef long long LL; const int N=300005; const int inf=0x7fffffff; int n,b ,c ,d ,rank[N*2],sa ,height ,f ,size ,mx1 ,mx2 ,mn1 ,mn2 ,a ,num ; LL ans ,mx ; char s ; void get_sa(int n,int m) { for (int i=1;i<=n;i++) b[s[i]]++; for (int i=1;i<=m;i++) b[i]+=b[i-1]; for (int i=n;i>=1;i--) c[b[s[i]]--]=i; int t=0; for (int i=1;i<=n;i++) { if (s[c[i]]!=s[c[i-1]]) t++; rank[c[i]]=t; } int j=1; while (j<=n) { for (int i=1;i<=n;i++) b[i]=0; for (int i=1;i<=n;i++) b[rank[i+j]]++; for (int i=1;i<=n;i++) b[i]+=b[i-1]; for (int i=n;i>=1;i--) c[b[rank[i+j]]--]=i; for (int i=1;i<=n;i++) b[i]=0; for (int i=1;i<=n;i++) b[rank[i]]++; for (int i=1;i<=n;i++) b[i]+=b[i-1]; for (int i=n;i>=1;i--) d[b[rank[c[i]]]--]=c[i]; t=0; for (int i=1;i<=n;i++) { if (rank[d[i]]!=rank[d[i-1]]||rank[d[i]]==rank[d[i-1]]&&rank[d[i]+j]!=rank[d[i-1]+j]) t++; c[d[i]]=t; } for (int i=1;i<=n;i++) rank[i]=c[i]; if (t==n) break; j*=2; } for (int i=1;i<=n;i++) sa[rank[i]]=i; } void get_height(int n) { int k=0; for (int i=1;i<=n;i++) { if (k) k--; int j=sa[rank[i]-1]; while (i+k<=n&&j+k<=n&&s[i+k]==s[j+k]) k++; height[rank[i]]=k; } } int find(int x) { if (f[x]==x) return x; f[x]=find(f[x]); return f[x]; } LL calc(int x) { return (LL)size[x]*(size[x]-1)/2; } void merge(int x,int y) { size[y]+=size[x];f[x]=y; if (mx1[x]!=-inf) { int w=mx1[x]; if (w>mx1[y]) mx2[y]=mx1[y],mx1[y]=w; else if (w>mx2[y]) mx2[y]=w; } if (mx2[x]!=-inf) { int w=mx2[x]; if (w>mx1[y]) mx2[y]=mx1[y],mx1[y]=w; else if (w>mx2[y]) mx2[y]=w; } if (mn1[x]!=inf) { int w=mn1[x]; if (w<mn1[y]) mn2[y]=mn1[y],mn1[y]=w; else if (w<mn2[y]) mn2[y]=w; } if (mn2[x]!=inf) { int w=mn2[x]; if (w<mn1[y]) mn2[y]=mn1[y],mn1[y]=w; else if (w<mn2[y]) mn2[y]=w; } } bool cmp(int a,int b) { return height[a]>height[b]; } int main() { scanf("%d",&n); scanf("%s",s+1); for (int i=1;i<=n;i++) scanf("%d",&a[i]); get_sa(n,200); get_height(n); for (int i=1;i<n;i++) num[i]=i+1; sort(num+1,num+n,cmp); for (int i=1;i<=n;i++) f[i]=i,mn1[i]=mx1[i]=a[sa[i]],mn2[i]=inf,mx2[i]=-inf,size[i]=1; for (int i=0;i<=n;i++) mx[i]=-(LL)inf*inf; int p=1; for (int i=n-1;i>=0;i--) { ans[i]=ans[i+1];mx[i]=mx[i+1]; while (height[num[p]]==i&&p<n) { int x=num[p]; ans[i]-=calc(find(x))+calc(find(x-1)); merge(find(x),find(x-1)); int w=find(x); ans[i]+=calc(w); mx[i]=max(mx[i],max((LL)mx1[w]*mx2[w],(LL)mn1[w]*mn2[w])); p++; } } for (int i=0;i<=n-1;i++) printf("%lld %lld\n",ans[i],mx[i]==-(LL)inf*inf?0:mx[i]); return 0; }
相关文章推荐
- bzoj4199[luoguP2178]品酒大会[noi2015] (后缀数组+并查集)
- 【BZOJ4199】品酒大会(NOI2015)-后缀数组+并查集
- 【BZOJ4199】[Noi2015]品酒大会 后缀数组+并查集
- [BZOJ4199][Noi2015]品酒大会(后缀数组+并查集)
- 【NOI2015】【BZOJ4199】品酒大会
- 【bzoj4199】[Noi2015]品酒大会 后缀自动机
- bzoj 4199 && NOI 2015 品酒大会
- bzoj 4199: [Noi2015]品酒大会 后缀树
- bzoj4199 [Noi2015]品酒大会
- [BZOJ4199][NOI2015]品酒大会 后缀数组
- 【BZOJ4199】【NOI2015】品酒大会(后缀数组)
- [BZOJ4199][Noi2015]品酒大会
- Bzoj4199:[NOI2015]品酒大会
- [BZOJ4199][NOI2015]品酒大会(后缀数组+单调栈+ST表)
- 【BZOJ 4199】[Noi2015]品酒大会 后缀自动机构造后缀树+dp
- 【BZOJ4199】【NOI2015】品酒大会(后缀数组)
- bzoj 4199: [Noi2015]品酒大会
- BZOJ 4199: [Noi2015]品酒大会( 后缀数组 + 并查集 )
- Bzoj4199:[NOI2015]品酒大会
- [BZOJ4199][NOI2015]品酒大会