他要求的就是lcp(x,y)>=i的(x,y)的个数和a[x]*a[y]的最大值

做一下后缀和,就只要求lcp=i的了

既然lcp(x,y)=min(h[rank[x]+1],..,[h[rank[y]]])

那么我们求出来对于每一个h,以它作为最小值的区间的左右端点就可以了,这个可以用单调栈,具体做法见Neat Tree(?哪里具体了)

假设L是i左面第一个h小于等于它的,R是i右面第一个小于它的(一定要一边有=一边没有,很关键)

那就相当于lcp(x,y)=h[i] ,rank[x]∈[L,i-1],rank[y]∈[i,R-1]

数量就是这两个区间大小乘一下,最大值是max(最大值之积,最小值之积)(因为会有负的),这个可以用ST表来做

貌似并查集也能做 但我哪会啊

写的这么辣鸡 开着O2才勉强水过洛谷 哪敢到bzoj去交啊

upd:(Time Limit: 10 Sec)

 #include<bits/stdc++.h>
#define pa pair<ll,ll>
#define CLR(a,x) memset(a,x,sizeof(a))
using namespace std;
typedef long long ll;
const int maxn=3e5+;
const ll inf=1e18; inline ll rd(){
ll x=;char c=getchar();int neg=;
while(c<''||c>''){if(c=='-') neg=-;c=getchar();}
while(c>=''&&c<='') x=x*+c-'',c=getchar();
return x*neg;
} int N,M,deli[maxn],sa[maxn<<],rnk[maxn<<],rnk1[maxn<<],tmp[maxn<<],h[maxn<<],cnt[maxn];
ll ans2[maxn],ma[maxn][],mn[maxn][],dt[maxn];
int stk[maxn],sh,rg[maxn];
char s[maxn]; inline void setsa(){
int i,j=,k;
for(i=;i<=N;i++) cnt[s[i]]=;
for(i=;i<=M;i++) cnt[i]+=cnt[i-];
for(i=N;i;i--) rnk[i]=cnt[s[i]];
for(k=;j!=N;k<<=){
// printf("%d %d %d\n",M,k,j);
CLR(cnt,);
for(i=;i<=N;i++) cnt[rnk[i+k]]++;
for(i=;i<=M;i++) cnt[i]+=cnt[i-];
for(i=N;i;i--) tmp[cnt[rnk[i+k]]--]=i;
CLR(cnt,);
for(i=;i<=N;i++) cnt[rnk[i]]++;
for(i=;i<=M;i++) cnt[i]+=cnt[i-];
for(i=N;i;i--) sa[cnt[rnk[tmp[i]]]--]=tmp[i];
memcpy(rnk1,rnk,sizeof(rnk));
i=;rnk[sa[]]=j=;
for(;i<=N;i++){
if(rnk1[sa[i]]!=rnk1[sa[i-]]||rnk1[sa[i]+k]!=rnk1[sa[i-]+k]) j++;
rnk[sa[i]]=j;
}M=j;
}
for(i=;i<=N;i++)
sa[rnk[i]]=i;
}
inline void seth(){
for(int i=,j=;i<=N;i++){
if(rnk[i]==) continue;
if(j) j--;
int x=sa[rnk[i]-];
while(i+j<=N&&x+j<=N&&s[i+j]==s[x+j]) j++;
h[rnk[i]]=j;
}
} inline void setma(){
for(int i=N;i;i--){
ma[i][]=mn[i][]=deli[sa[i]];
for(int j=;i+(<<j)-<=N;j++){
int k=i+(<<(j-));
ma[i][j]=max(ma[i][j-],ma[k][j-]);
mn[i][j]=min(mn[i][j-],mn[k][j-]);
}
}
} inline pa getma(int l,int r){
int k=log2(r-l+);
return make_pair(max(ma[l][k],ma[r-(<<k)+][k]),min(mn[l][k],mn[r-(<<k)+][k]));
} void solve(){
for(int i=;i<=N;i++){
while(sh&&h[stk[sh]]>h[i])
rg[stk[sh--]]=i;
stk[++sh]=i;
}while(sh) rg[stk[sh--]]=N+;
for(int i=N;i;i--){
while(sh&&h[stk[sh]]>=h[i]){
int r=rg[stk[sh]]-;
pa x=getma(i,stk[sh]-),y=getma(stk[sh],r);
ans2[h[stk[sh]]]=max(ans2[h[stk[sh]]],max(x.first*y.first,x.second*y.second));
dt[h[stk[sh]]]+=1ll*(stk[sh]-i)*(r-stk[sh]+);
sh--;
}
stk[++sh]=i;
}
} int main(){
// freopen("testdata.in","r",stdin);
// freopen("aa.out","w",stdout);
int i,j,k;
N=rd();
scanf("%s",s+);
for(i=;i<=N;i++)
deli[i]=rd();
M=;setsa();
seth();
setma();
CLR(ans2,-);
solve();
for(i=N-;i>=;i--) dt[i]+=dt[i+],ans2[i]=max(ans2[i],ans2[i+]);
for(i=;i<N;i++)
printf("%lld %lld\n",dt[i],dt[i]?ans2[i]:);
return ;
}

luogu2178/bzoj4199 品酒大会 (SA+单调栈)的更多相关文章

  1. Luogu2178 NOI2015 品酒大会 SA、并查集

    传送门 感觉题目讲的很不清楚-- 题目意思就是给出一个长度为\(n\)的字符串,求对于\(r=0,1,...,n-1\),求出\(LCP(suffix_p,suffix_q) \geq r\)的无序数 ...

  2. Codeforces 802I Fake News (hard) (SA+单调栈) 或 SAM

    原文链接http://www.cnblogs.com/zhouzhendong/p/9026184.html 题目传送门 - Codeforces 802I 题意 求一个串中,所有本质不同子串的出现次 ...

  3. Codeforces 873F Forbidden Indices 字符串 SAM/(SA+单调栈)

    原文链接https://www.cnblogs.com/zhouzhendong/p/9256033.html 题目传送门 - CF873F 题意 给定长度为 $n$ 的字符串 $s$,以及给定这个字 ...

  4. Codeforces 1073G Yet Another LCP Problem $SA$+单调栈

    题意 给出一个字符串\(s\)和\(q\)个询问. 每次询问给出两个长度分别为\(k,l\)的序列\(a\)和序列\(b\). 求\(\sum_{i=1}^{k}\sum_{j=1}^{l}lcp(s ...

  5. BZOJ3238 [Ahoi2013]差异 SA+单调栈

    题面 戳这里 题解 考虑把要求的那个东西拆开算,前面一个东西像想怎么算怎么算,后面那个东西在建出\(height\)数组后相当于是求所有区间\(min\)的和*2,单调栈维护一波即可. #includ ...

  6. poj 3415 Common Substrings【SA+单调栈】

    把两个串中间加一个未出现字符接起来,然后求SA 然后把贡献统计分为两部分,在排序后的后缀里,属于串2的后缀和排在他前面属于串1的后缀的贡献和属于串1的后缀和排在他前面属于串2的后缀的贡献 两部分分别作 ...

  7. [NOI2015]品酒大会(SA数组)

    [NOI2015]品酒大会 题目描述 一年一度的"幻影阁夏日品酒大会"隆重开幕了.大会包含品尝和趣味挑战 两个环节,分别向优胜者颁发"首席品酒家"和" ...

  8. 洛谷4248 AHOI2013差异 (后缀数组SA+单调栈)

    补博客! 首先我们观察题目中给的那个求\(ans\)的方法,其实前两项没什么用处,直接\(for\)一遍就求得了 for (int i=1;i<=n;i++) ans=ans+i*(n-1); ...

  9. 【POJ3415】 Common Substrings (SA+单调栈)

    这道是求长度不小于 k 的公共子串的个数...很不幸,我又TLE了... 解法参考论文以及下面的链接 http://www.cnblogs.com/vongang/archive/2012/11/20 ...

随机推荐

  1. 面试3——java集合类总结(List)

    1.集合类 数组:可以存储对象,也可以存储基本数据类型,但是一次只能存储一种类型,且长度一定,不可改变. 集合:只能存储对象,长度可变,可以存储不同类型的对象.Java集合类主要有三种:set,lis ...

  2. ORA-12638:Credential retrieval failed(身份证明检索失败)解决方法

    版本:oracle 11g 解决方法: 在sqlnet.ora中设置SQLNET.AUTHENTICATION_SERVICES= 0.本人亲自验证,可以解决此问题. 网上说设置SQLNET.AUTH ...

  3. pyenv+virtual 笔记

    Pyenv + virtualEnv 设置 安装这两个组件是为了适应不同版本的python在同一个系统下的运行:例如现在最明显就是python2.7和python3.6的两个版本,很多库依旧是使用了P ...

  4. JAVA CAS原理浅谈

    java.util.concurrent包完全建立在CAS之上的,没有CAS就不会有此包.可见CAS的重要性. CAS CAS:Compare and Swap, 翻译成比较并交换. java.uti ...

  5. python基础知识小结-运维笔记

    接触python已有一段时间了,下面针对python基础知识的使用做一完整梳理:1)避免‘\n’等特殊字符的两种方式: a)利用转义字符‘\’ b)利用原始字符‘r’ print r'c:\now' ...

  6. Linux下selinux简单梳理

    在linux环境下执行某些程序时,偶尔会遇到来一个关于selinux的强制模式不可执行的情况,这种情况下需要关闭selinux或者将enforcing改为permissive模式后才能进行执行.sel ...

  7. 修改sga_max_size大小后重启数据库报 ORA-00851

    http://blog.itpub.net/30150152/viewspace-1449898/

  8. A. Make a triangle!

    题意 给你三条边a,b,c问使得构成三角形,需要增加的最少长度是多少 思路 数学了啦 代码 #include<bits/stdc++.h> using namespace std; #de ...

  9. Python学习笔记 -- 第四章

    高阶函数 变量可以指向函数 f=abs f(-10) 10 变量f指向abs函数,直接调用abs()函数和调用f()完全相同 传入参数 变量可以指向函数,函数的参数可以接收另一个函数的参数,这种函数成 ...

  10. Xshell连接到centos提示Could not connect to (port 22): Connection failed

    关于XShell连接虚拟机中的centos系统的问题,在连接的时候报错如下: 一开始以为是系统的问题,但是搞了很久,才发现是虚拟机这个软件本身的问题,的确坑啊!所以解决方法也很简单.在编辑菜单那里打开 ...