bzoj3473 字符串
一下午都给这题了……
好不容易写完之后去查论文才发现自己写了一个极其麻烦的做法……这人没救了
……
可以对所有串建一个广义后缀自动机,统计每个节点属于几个串可以用树链的并搞出来,剩下的就是在匹配的过程中统计parent树上所有祖先的right集合大小*串长区间之和就行了。
注意每次right集合不一样,可以用树状数组维护right集合大小。至于查询,直接暴力找所有祖先即可,可以证明复杂度是$O(n\sqrt n)$的(一开始还觉得自己复杂度错了……),总的复杂度就是$O(n\sqrt n\log n)$,由于数据没有卡这种做法,因此那个$\sqrt n$是跑不满的。
代码很长,写到自己都想吐……
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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]];}
上午写了一大半没来得及调就吃饭去了,下午看不懂上午写的代码了,索性删掉重写,写完测了测样例结果错的离谱,然后发现自己思路翻车了,好不容易想清楚之后索性再删了重写,写到一半又发现自己思路翻车了,又删了重写……然后一下午就过去了……我好菜啊……
233333333