zoukankan      html  css  js  c++  java
  • bzoj3473 字符串

    传送门

    一下午都给这题了……

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

    ……

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

    注意每次right集合不一样,可以用树状数组维护right集合大小。至于查询,直接暴力找所有祖先即可,可以证明复杂度是$O(nsqrt n)$的(一开始还觉得自己复杂度错了……),总的复杂度就是$O(nsqrt nlog 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
    ",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
    ",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
    ",f[x][0]);
    122     return f[x][0];
    123 }
    124 long long match(int id){//printf("match(%d)
    ",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)
    ",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

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

  • 相关阅读:
    无旋转Treap简介
    bzoj 4318 OSU!
    bzoj 1419 Red is good
    bzoj 4008 亚瑟王
    bzoj 1014 火星人prefix
    更多的莫队
    bzoj 3489 A simple rmq problem
    洛谷 2056 采花
    NOIP 2017 游(划水)记
    UVa 11997 K Smallest Sums
  • 原文地址:https://www.cnblogs.com/hzoier/p/6560654.html
Copyright © 2011-2022 走看看