[BZOJ4199][UOJ#131]【NOI2015】品酒大会
2017-12-25 21:03
405 查看
Description
给出一个长度为 n 的字符串,每一位有一个权值 val。定义两个位字符为 r 相似,是指分别从这两个字符开始,到后面的 r 个字符都相等。两个 r 相似的字符还有一个权值为这两个字符权值的乘积。问对于 r = 0, 1, 2, … , n - 1,统计出有多少种方法可以选出 2 个“r 相似”的字符,并回答选择 2 个”r 相似”的字符可以得到的权值的最大值。n<=3*10^5
|val| <=10^9
Solution
i和j这两个位置的字符r相似其实就是它们开头的后缀的最长公共前缀大于等于r那么可以先将height构造出来
对于两个位置i和j,它们排名之间的height的最小值要大于等于r
按照height排序,从大到小做,每扫到一个height那么就利用并查集将它和它的前一名缩起来,并更新相应的r的答案,一开始这个答案还要从之前的继承过来
计算方案数,那么只需要维护并查集时集合的size,合并就相乘计入答案
计算最大值,因为有可能有负数,那么维护集合的最大值和最小值,看乘起来哪个更大
Code
#include <cstdio> #include <cstdlib> #include <iostream> #include <algorithm> #include <cmath> #include <cstring> #define fo(i,a,b) for(int i=a;i<=b;i++) #define fod(i,a,b) for(int i=a;i>=b;i--) #define imax(a,b) ((a>b)?a:b) #define N 300005 #define LL long long using namespace std; char st ; int s2 ,SA ,rank ,r1 ,ct ,n,height ,d ,f ; LL a ,ans ,cnt ,sz ,mx ,mi ; void prp() { int m=0; memset(ct,0,sizeof(ct)); fo(i,1,n) ct[rank[i]=st[i]-'a'+1]++,m=imax(m,rank[i]); fo(i,1,m) ct[i]+=ct[i-1]; fod(i,n,1) SA[ct[rank[i]]--]=i; for(int j=1,k=0;k<n;j<<=1,m=k) { memset(ct,0,sizeof(ct)); int p=0; fo(i,n-j+1,n) s2[++p]=i; fo(i,1,n) if(SA[i]>j) s2[++p]=SA[i]-j; fo(i,1,n) ct[rank[s2[i]]]++; fo(i,1,m) ct[i]+=ct[i-1]; fod(i,n,1) SA[ct[rank[s2[i]]]--]=s2[i]; r1[SA[1]]=k=1; fo(i,2,n) r1[SA[i]]=(rank[SA[i]]==rank[SA[i-1]]&&rank[SA[i]+j]==rank[SA[i-1]+j])?k:++k; fo(i,1,n) rank[i]=r1[i]; } } void geth() { height[1]=0; fo(i,1,n) { if(rank[i]==1) continue; int p=imax(0,height[rank[i-1]]-1); while(st[i+p]==st[SA[rank[i]-1]+p]) p++; height[rank[i]]=p; } } bool cmp(int x,int y) { return height[x]>height[y]; } int getf(int k) { if(f[k]==0||f[k]==k) return k; return f[k]=getf(f[k]); } int main() { cin>>n; scanf("\n%s",st+1); fo(i,1,n) scanf("%lld",&a[i]); prp(); geth(); fo(i,1,n) d[i]=i,sz[i]=1,mx[i]=mi[i]=a[SA[i]]; sort(d+1,d+1+n,cmp); fo(i,0,n) ans[i]=-7000000000000000000; fo(i,1,n) { int w=height[d[i]]; if(w!=height[d[i-1]]) cnt[w]+=cnt[height[d[i-1]]],ans[w]=max(ans[w],ans[height[d[i-1]]]); if(d[i]==1) continue; int fx=getf(d[i]),fy=getf(d[i]-1); cnt[w]+=sz[fx]*sz[fy]; ans[w]=max(ans[w],max(mx[fx]*mx[fy],mi[fx]*mi[fy])); f[fx]=fy,sz[fy]+=sz[fx],mx[fy]=max(mx[fy],mx[fx]),mi[fy]=min(mi[fy],mi[fx]); } fod(i,n-1,0) { ans[i]=max(ans[i],ans[i+1]); if(cnt[i]==0) cnt[i]=cnt[i+1]; } fo(i,0,n-1) { if(ans[i]==-7000000000000000000) ans[i]=0; printf("%lld %lld\n",cnt[i],ans[i]); } }
相关文章推荐
- uoj 131/bzoj 4199 [NOI2015]品酒大会 后缀树+树d
- BZOJ4199/UOJ131 [Noi2015]品酒大会
- 【UOJ131】【BZOJ4199】【NOI2015】品酒大会(后缀数组)
- [BZOJ4199][Noi2015]品酒大会 树形DP+后缀自动机
- 【BZOJ4199】[Noi2015]品酒大会 后缀数组+并查集
- bzoj4199 [Noi2015]品酒大会
- [NOI2015][BZOJ4199] 品酒大会|后缀数组|并查集
- bzoj 4199: [Noi2015]品酒大会 (后缀自动机+DP)
- [BZOJ4199][NOI2015]品酒大会
- BZOJ 4199: [Noi2015]品酒大会/UOJ #131. 【NOI2015】品酒大会 后缀自动机 树形dp / 后缀数组 单调栈
- [BZOJ4199][Noi2015]品酒大会(后缀数组+并查集)
- bzoj4199 [Noi2015]品酒大会
- bzoj4199[luoguP2178]品酒大会[noi2015] (后缀数组+并查集)
- [bzoj4199][NOI2015]品酒大会
- [BZOJ4199] [Noi2015]品酒大会
- Bzoj4199:[NOI2015]品酒大会
- 【NOI2015】bzoj4199 品酒大会【解法一】
- 【NOI2015】【BZOJ4199】品酒大会
- Bzoj4199:[NOI2015]品酒大会
- bzoj千题计划257:bzoj4199: [Noi2015]品酒大会