码迷,mamicode.com
首页 > 编程语言 > 详细

字符串(后缀数组||SAM):NOI2015 品酒大会

时间:2016-07-18 03:07:47      阅读:228      评论:0      收藏:0      [点我收藏+]

标签:

技术分享技术分享

  这道题可以转化为计数类问题。

  若使用后缀数组,那么答案就是所有位置二元组(i,j)的lcp对0~lcp答案段的贡献。然后发现若一个二元组有x的贡献,那么对x-1有同样的贡献,考虑先求出lcp(max)的答案,再传给lcp(max-1)等等,复杂度是O(N)的。

  若用SAM,那么需要求的答案在x与fa[x]的转移之间,因为后缀自动机中每个点所代表的出现位置和出现次数是相等的,可以合并,事实上还是用到了后缀数组的叠加的原理,从叶子节点一路传上去……………………………………………

  还有要注意INF要足够大。

  1 #include <algorithm>
  2 #include <iostream>
  3 #include <cstring>
  4 #include <cstdio>
  5 using namespace std;
  6 const int maxn=300010;
  7 const long long INF=3000000000000000000LL;
  8 int rank[maxn],sa[maxn],r[maxn],lcp[maxn];
  9 int Wa[maxn],Wb[maxn],Wv[maxn],Ws[maxn];
 10 
 11 bool cmp(int *p,int i,int j,int l){
 12     return p[i]==p[j]&&p[i+l]==p[j+l];
 13 }
 14 
 15 void DA(int n,int m){
 16     int i,h,p=1,*x=Wa,*y=Wb;
 17     for(i=0;i<m;i++)Ws[i]=0;
 18     for(i=0;i<n;i++)Ws[x[i]=r[i]]++;
 19     for(i=1;i<m;i++)Ws[i]+=Ws[i-1];
 20     for(i=n-1;i>=0;i--)sa[--Ws[x[i]]]=i;
 21     
 22     
 23     for(h=1;p<n;m=p,h<<=1){
 24         for(i=n-h,p=0;i<n;i++)y[p++]=i;
 25         for(i=0;i<n;i++)
 26             if(sa[i]>=h)y[p++]=sa[i]-h;
 27         for(i=0;i<m;i++)Ws[i]=0;
 28         for(i=0;i<n;i++)Ws[Wv[i]=x[y[i]]]++;
 29         for(i=1;i<m;i++)Ws[i]+=Ws[i-1];
 30         for(i=n-1;i>=0;i--)sa[--Ws[Wv[i]]]=y[i];
 31         for(p=1,swap(x,y),x[sa[0]]=0,i=1;i<n;i++)
 32             x[sa[i]]=cmp(y,sa[i-1],sa[i],h)?p-1:p++;        
 33     }
 34 }
 35 
 36 void LCP(int n){
 37     int i,j,k=0;
 38     for(i=1;i<=n;i++)rank[sa[i]]=i;
 39     for(i=0;i<n;lcp[rank[i++]]=k)
 40         for(k?k--:k,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);
 41 }
 42 
 43 int n;
 44 char s[maxn];
 45 
 46 struct Node{
 47     int x,y,v;
 48     Node(int x_=0,int y_=0,int v_=0):x(x_),y(y_),v(v_){}
 49     friend bool operator <(Node a,Node b){
 50         return a.v>b.v;
 51     }
 52 }st[maxn];
 53 int w[maxn],fa[maxn];
 54 long long mx[maxn],mn[maxn];
 55 long long sz[maxn],ans[maxn],sum[maxn];
 56 
 57 int Find(int x){
 58     return fa[x]==x?x:fa[x]=Find(fa[x]);
 59 }
 60 
 61 int main(){
 62 #ifndef ONLINE_JUDGE
 63     freopen("savour.in","r",stdin);
 64     freopen("savour.out","w",stdout);
 65 #endif    
 66     scanf("%d%s",&n,s);
 67     for(int i=0;i<n;i++){
 68         scanf("%d",&w[i]);
 69         r[i]=s[i];
 70     }    
 71     DA(n+1,128);LCP(n);
 72     
 73     for(int i=2;i<=n;i++)
 74         st[i-1]=Node(sa[i],sa[i-1],lcp[i]);
 75     sort(st+1,st+n);
 76     
 77     for(int i=0;i<n;i++){
 78         fa[i]=i;sz[i]=1;
 79         mx[i]=mn[i]=w[i];
 80         sum[i]=-INF;
 81     }
 82     
 83     for(int i=st[1].v,j=1;i>=0;i--){
 84         ans[i]=ans[i+1];
 85         sum[i]=sum[i+1];
 86         while(j<n&&st[j].v==i){
 87             int x=Find(st[j].x),y=Find(st[j].y);
 88             sum[i]=max(sum[i],mx[x]*mx[y]);
 89             sum[i]=max(sum[i],mn[x]*mn[y]);
 90             ans[i]+=sz[x]*sz[y];
 91             fa[x]=y;sz[y]+=sz[x];
 92             mn[y]=min(mn[x],mn[y]);
 93             mx[y]=max(mx[x],mx[y]);
 94             j+=1;
 95         }        
 96     }    
 97     
 98     for(int i=0;i<n;i++){
 99         if(ans[i]==0)sum[i]=0;
100         printf("%lld %lld\n",ans[i],sum[i]);
101     }
102     return 0;    
103 }

  这个是SAM,小了一个log的复杂度,实际上没快多少……

 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 using namespace std;
 5 const int maxn=600010;
 6 const long long INF=1LL<<60;
 7 int n,cnt,last,ord[maxn],c[maxn];
 8 int fa[maxn],ch[maxn][26],len[maxn];
 9 long long tmp[maxn],mx[maxn],mn[maxn],w[maxn];
10 long long num[maxn],tot[maxn],t1[maxn],t2[maxn];
11 char s[maxn];
12 
13 struct SAM{
14     SAM(){cnt=last=1;}
15     void Insert(int c,int t){
16         int p=last,np=last=++cnt;tmp[np]=1;
17         len[np]=len[p]+1;mx[cnt]=mn[cnt]=w[t];
18         while(p&&!ch[p][c])ch[p][c]=np,p=fa[p];
19         if(!p)fa[np]=1;
20         else{
21             int q=ch[p][c],nq;
22             if(len[q]==len[p]+1)
23                 fa[np]=q;
24             else{
25                 len[nq=++cnt]=len[p]+1;
26                 mx[cnt]=-INF;mn[cnt]=INF;
27                 memcpy(ch[nq],ch[q],sizeof(ch[q]));
28                 fa[nq]=fa[q];fa[q]=fa[np]=nq;
29                 while(ch[p][c]==q)ch[p][c]=nq,p=fa[p];
30             }
31         }
32         return; 
33     }
34     
35     void Solve(){
36         for(int i=1;i<=cnt;i++)c[len[i]]++;
37         for(int i=1;i<=len[last];i++)c[i]+=c[i-1];
38         for(int i=1;i<=cnt;i++)ord[c[len[i]]--]=i;
39         for(int i=1;i<=cnt;i++)t2[i]=num[i]=-INF;
40         mn[1]=INF;mx[1]=-INF;
41         
42         for(int i=cnt;i>=1;i--){
43             int p=ord[i];
44             t1[fa[p]]+=tmp[fa[p]]*tmp[p];
45             tmp[fa[p]]+=tmp[p];
46             if(mn[fa[p]]!= INF)t2[fa[p]]=max(t2[fa[p]],mn[p]*mn[fa[p]]);
47             if(mx[fa[p]]!=-INF)t2[fa[p]]=max(t2[fa[p]],mx[p]*mx[fa[p]]);
48             mn[fa[p]]=min(mn[fa[p]],mn[p]);
49             mx[fa[p]]=max(mx[fa[p]],mx[p]);
50         }
51         
52         for(int i=1;i<=cnt;i++){
53             tot[len[i]]+=t1[i];
54             num[len[i]]=max(num[len[i]],t2[i]);
55         }
56         
57         for(int i=n-2;i>=0;i--){
58             tot[i]+=tot[i+1];
59             num[i]=max(num[i],num[i+1]);
60         }
61         
62         for(int i=0;i<n;i++)
63             printf("%lld %lld\n",tot[i],tot[i]?num[i]:0);
64     }
65 }sam;
66 
67 int main(){
68     freopen("savour.in","r",stdin);
69     freopen("savour.out","w",stdout);
70     scanf("%d%s",&n,s);
71     for(int i=1;i<=n;i++)scanf("%lld",&w[i]);
72     for(int i=n;i;i--)sam.Insert(s[i-1]-a,i);
73     sam.Solve();    
74     return 0;
75 }

 

字符串(后缀数组||SAM):NOI2015 品酒大会

标签:

原文地址:http://www.cnblogs.com/TenderRun/p/5679804.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!