bzoj3473 字符串

传送门

一下午都给这题了……

好不容易写完之后去查论文才发现自己写了一个极其麻烦的做法……这人没救了

……

可以对所有串建一个广义后缀自动机,统计每个节点属于几个串可以用树链的并搞出来,剩下的就是在匹配的过程中统计parent树上所有祖先的right集合大小*串长区间之和就行了。

注意每次right集合不一样,可以用树状数组维护right集合大小。至于查询,直接暴力找所有祖先即可,可以证明复杂度是$O(n\sqrt n)$的(一开始还觉得自己复杂度错了……),总的复杂度就是$O(n\sqrt n\log n)$,由于数据没有卡这种做法,因此那个$\sqrt n$是跑不满的。

代码很长,写到自己都想吐……

  1 /**************************************************************
  2     Problem: 3473
  3     User: _Angel_
  4     Language: C++
  5     Result: Accepted
  6     Time:812 ms
  7     Memory:75436 kb
  8 ****************************************************************/
  9 #include<cstdio>
 10 #include<cstring>
 11 #include<algorithm>
 12 #include<vector>
 13 using namespace std;
 14 const int maxn=200010;
 15 void insert(const char*,int&,vector<int>&);
 16 void bfs();
 17 int expand(int,int);
 18 void dfs(int);
 19 int LCA(int,int);
 20 long long match(int);
 21 void add(int,int);
 22 int query(int);
 23 bool cmp(int,int);
 24 int root=0,ch[maxn][26]={{0}},trie_cnt=0,last[maxn],c[maxn]={0},q[maxn];
 25 int val[maxn]={0},par[maxn]={0},go[maxn][26]={{0}},cnt=0;
 26 long long sum[maxn]={0};
 27 int dfn[maxn]={0},finish[maxn],tim=0,f[maxn][20]={{0}},d[maxn]={0},sm[maxn]={0},vis[maxn];
 28 vector<int>G[maxn],iter[maxn];
 29 char s[maxn];
 30 vector<char>str[maxn];
 31 int n,k,lgn=0;
 32 int main(){
 33     scanf("%d%d",&n,&k);
 34     for(int i=1;i<=n;i++){
 35         scanf("%s",s);
 36         str[i]=vector<char>(s,s+strlen(s));
 37         insert(s,root,iter[i]);
 38     }
 39     bfs();
 40     for(int i=2;i<=cnt;i++)G[par[i]].push_back(i);
 41     dfs(1);//for(int i=1;i<=cnt;i++)printf("x=%d dfn=%d finish=%d\n",i,dfn[i],finish[i]);
 42     for(int i=1;i<=cnt;i++)f[i][0]=par[i];
 43     for(int j=1;j<=lgn;j++)for(int i=1;i<=cnt;i++)f[i][j]=f[f[i][j-1]][j-1];
 44     for(int id=1;id<=n;id++){
 45         sort(iter[id].begin(),iter[id].end(),cmp);
 46         sm[last[iter[id][0]]]++;
 47         for(int i=1;i<(int)iter[id].size();i++){
 48             sm[last[iter[id][i]]]++;
 49             sm[LCA(last[iter[id][i]],last[iter[id][i-1]])]--;
 50         }
 51     }
 52     for(int i=1;i<=cnt;i++)c[val[i]+1]++;
 53     for(int i=1;i<=cnt;i++)c[i]+=c[i-1];
 54     for(int i=1;i<=cnt;i++)q[++c[val[i]]]=i;
 55     for(int i=cnt;i;i--)sm[par[q[i]]]+=sm[q[i]];
 56     memset(c,0,sizeof(c));
 57     for(int i=1;i<=n;i++)printf("%lld ",match(i));
 58     return 0;
 59 }
 60 void insert(const char *c,int &rt,vector<int>&a){
 61     if(!rt)rt=++trie_cnt;
 62     a.push_back(rt);
 63     if(*c)insert(c+1,ch[rt][*c-'a'],a);
 64 }
 65 void bfs(){
 66     int x,head=0,tail=0;
 67     last[root]=++cnt;
 68     q[tail++]=root;
 69     while(head!=tail){
 70         x=q[head++];
 71         for(int c=0;c<26;c++)if(ch[x][c]){
 72             last[ch[x][c]]=expand(c,last[x]);
 73             q[tail++]=ch[x][c];
 74         }
 75     }
 76 }
 77 int expand(int c,int p){
 78     int np=++cnt;
 79     val[np]=val[p]+1;
 80     while(p&&!go[p][c]){
 81         go[p][c]=np;
 82         p=par[p];
 83     }
 84     if(!p)par[np]=1;
 85     else{
 86         int q=go[p][c];
 87         if(val[q]==val[p]+1)par[np]=q;
 88         else{
 89             int nq=++cnt;
 90             val[nq]=val[p]+1;
 91             memcpy(go[nq],go[q],sizeof(go[q]));
 92             par[nq]=par[q];
 93             par[np]=par[q]=nq;
 94             while(p&&go[p][c]==q){
 95                 go[p][c]=nq;
 96                 p=par[p];
 97             }
 98         }
 99     }
100     return np;
101 }
102 void dfs(int x){
103     dfn[x]=++tim;
104     d[x]=d[par[x]]+1;
105     while((1<<lgn)<d[x])lgn++;
106     for(int i=0;i<(int)G[x].size();i++)dfs(G[x][i]);
107     finish[x]=tim;
108 }
109 int LCA(int x,int y){//printf("LCA(%d,%d)=",x,y);
110     if(d[x]!=d[y]){
111         if(d[x]<d[y])swap(x,y);
112         for(int i=lgn;i>=0;i--)if(d[f[x][i]]>=d[y])x=f[x][i];
113     }
114     if(x==y){
115         //printf("%d\n",x);
116         return x;
117     }
118     for(int i=lgn;i>=0;i--)if(f[x][i]!=f[y][i]){
119         x=f[x][i];
120         y=f[y][i];
121     }//printf("%d\n",f[x][0]);
122     return f[x][0];
123 }
124 long long match(int id){//printf("match(%d)\n",id);
125     for(int i=0;i<(int)iter[id].size();i++)add(dfn[last[iter[id][i]]],1);
126     long long ans=0;
127     for(int i=0;i<(int)iter[id].size();i++)for(int x=last[iter[id][i]];x&&vis[x]!=id;x=par[x]){
128         vis[x]=id;
129         if(sm[x]>=k)ans+=(long long)(val[x]-val[par[x]])*(query(finish[x])-query(dfn[x]-1));
130     }
131     for(int i=0;i<(int)iter[id].size();i++)add(dfn[last[iter[id][i]]],-1);
132     return ans;
133 }
134 void add(int x,int d){//printf("add(%d,%d)\n",x,d);
135     while(x<=cnt){
136         c[x]+=d;
137         x+=x&-x;
138     }
139 }
140 int query(int x){
141     int ans=0;
142     while(x){
143         ans+=c[x];
144         x&=x-1;
145     }
146     return ans;
147 }
148 bool cmp(int x,int y){return dfn[last[x]]<dfn[last[y]];}
View Code

上午写了一大半没来得及调就吃饭去了,下午看不懂上午写的代码了,索性删掉重写,写完测了测样例结果错的离谱,然后发现自己思路翻车了,好不容易想清楚之后索性再删了重写,写到一半又发现自己思路翻车了,又删了重写……然后一下午就过去了……我好菜啊……

posted @ 2017-03-16 17:27  AntiLeaf  阅读(163)  评论(0编辑  收藏  举报