Frequency of String CodeForces

http://codeforces.com/contest/963/problem/D

题解:https://www.cnblogs.com/Blue233333/p/8881614.html

记M为n个串的总长,L为s的长度

询问串的不同的长度只会有sqrt(M)级别个

(最差的情况是串长为1,2,3,...,x,此时M=(x+1)x/2,因此x是sqrt(M)级别的)

s的子串中,长度为特定值k的子串个数是L级别的,

由于各个字符串互不相同,这就相当于n个串中所有长度为k的串,分别计算出它们在s中出现次数,各个计算结果的和是L级别的

因此只要设计对于每一个询问串都是O(串长+出现次数)的算法就行了


花了好长时间写了个后缀自动机字符串匹配啊。。。。莫不是搞复杂了

代码1.(using连用多个是c++17的,曾经还CE了)

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<set>
  5 #include<queue>
  6 using namespace std;
  7 typedef long long LL;
  8 char s[100010],ss[100100];
  9 int ll,x[100100],l2;
 10 int pp[100100];
 11 vector<int> vv[200100];
 12 set<int> sss[200100];
 13 int n,ans[100100];
 14 int lll[100100];
 15 namespace SAM
 16 {
 17     int mem,np,root;
 18     int len[200100],par[200100];
 19     int trans[200100][26];
 20     int posl[200100],posr[200100];
 21     void append(int ch)
 22     {
 23         int p=np;np=++mem;len[np]=len[p]+1;
 24         for(;p&&!trans[p][ch];p=par[p])    trans[p][ch]=np;
 25         if(!p)    par[np]=root;
 26         else
 27         {
 28             int q=trans[p][ch];
 29             if(len[q]==len[p]+1)    par[np]=q;
 30             else
 31             {
 32                 int nq=++mem;par[nq]=par[q];par[q]=par[np]=nq;
 33                 memcpy(trans[nq],trans[q],sizeof(trans[nq]));len[nq]=len[p]+1;
 34                 for(;p&&trans[p][ch]==q;p=par[p])    trans[p][ch]=nq;
 35             }
 36         }
 37     }
 38     void build()
 39     {
 40         np=root=++mem;
 41         int i,now;
 42         for(i=1;i<=ll;i++)    append(s[i]-'a'),pp[i]=np,sss[np].insert(i);
 43         for(i=1;i<=ll;i++)
 44         {
 45             for(now=pp[i];now!=root&&!posr[now]&&!posl[now];now=par[now])
 46             {
 47                 posl[now]=i-len[par[now]];posr[now]=i-len[now]+1;
 48             }
 49         }
 50     }
 51 }
 52 namespace ST
 53 {
 54     int ch[200100][26];
 55     using SAM::par;
 56     void build()
 57     {
 58         int i;
 59         for(i=1;i<=SAM::mem;i++)
 60         {
 61             if(par[i])
 62             {
 63                 ch[par[i]][s[SAM::posl[i]]-'a']=i;
 64             }
 65         }
 66     }
 67     /*
 68     void out()
 69     {
 70         int i,j,k;using SAM::len,SAM::posl,SAM::posr;
 71         for(i=1;i<=SAM::mem;i++)
 72         {
 73             for(j=0;j<26;j++)
 74             {
 75                 if(ch[i][j])
 76                 {
 77                     printf("%d %d ",i,ch[i][j]);
 78                     for(k=posl[ch[i][j]];k>=posr[ch[i][j]];k--)    putchar(s[k]);
 79                     puts("");
 80                 }
 81             }
 82         }
 83     }
 84     */
 85 }
 86 void work(int tt)
 87 {
 88     using SAM::root,SAM::posl,SAM::posr,ST::ch;
 89     int i,now=root,j,k;
 90     for(i=l2;i>=1;)
 91     {
 92         now=ch[now][ss[i]-'a'];
 93         if(!now)    return;
 94         for(j=i,k=posl[now];j>=1&&k>=posr[now];j--,k--)
 95             if(ss[j]!=s[k])
 96                 return;
 97         i-=posl[now]-posr[now]+1;
 98         //printf("b%d %d %d %d
",now,i,posl[now],posr[now]);
 99     }
100     vv[now].push_back(tt);//printf("a%d
",now);
101 }
102 queue<int> q;int in[200100];
103 void work2()
104 {
105     using SAM::mem,SAM::par;
106     int i,j,t,l,r;vector<int> tmp;
107     for(i=1;i<=mem;i++)    if(par[i])    in[par[i]]++;
108     for(i=1;i<=mem;i++)    if(!in[i])    q.push(i);
109     while(!q.empty())
110     {
111         t=q.front();q.pop();
112         if(vv[t].size())
113         {
114             tmp.clear();
115             for(auto k:sss[t])    tmp.push_back(k);
116             //for(i=0;i<tmp.size();i++)    printf("%d ",tmp[i]);puts("");
117         }
118         for(auto p:vv[t])
119         {
120             for(i=0,j=x[p]-1;j<tmp.size();i++,j++)
121             {
122                 ans[p]=min(ans[p],tmp[j]-tmp[i]+lll[p]);
123             }
124         }
125         if(par[t])
126         {
127             if(sss[par[t]].size()<sss[t].size())    swap(sss[par[t]],sss[t]);
128             for(auto k:sss[t])    sss[par[t]].insert(k);
129             sss[t].clear();
130             in[par[t]]--;
131             if(!in[par[t]])    q.push(par[t]);
132         }
133     }
134 }
135 int main()
136 {
137     int i;
138     scanf("%s",s+1);ll=strlen(s+1);
139     SAM::build();ST::build();
140     //ST::out();return 0;
141     scanf("%d",&n);
142     for(i=1;i<=n;i++)
143     {
144         scanf("%d%s",&x[i],ss+1);l2=lll[i]=strlen(ss+1);
145         work(i);
146     }
147     memset(ans,0x3f,sizeof(ans));
148     work2();
149     for(i=1;i<=n;i++)
150         printf("%d
",ans[i]==0x3f3f3f3f?-1:ans[i]);
151     return 0;
152 }
View Code

代码2:

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<set>
  5 #include<queue>
  6 using namespace std;
  7 typedef long long LL;
  8 char s[100010],ss[100100];
  9 int ll,x[100100],l2;
 10 int pp[100100];
 11 vector<int> vv[200100];
 12 set<int> sss[200100];
 13 int n,ans[100100];
 14 int lll[100100];
 15 namespace SAM
 16 {
 17     int mem,np,root;
 18     int len[200100],par[200100];
 19     int trans[200100][26];
 20     int posl[200100],posr[200100];
 21     void append(int ch)
 22     {
 23         int p=np;np=++mem;len[np]=len[p]+1;
 24         for(;p&&!trans[p][ch];p=par[p])    trans[p][ch]=np;
 25         if(!p)    par[np]=root;
 26         else
 27         {
 28             int q=trans[p][ch];
 29             if(len[q]==len[p]+1)    par[np]=q;
 30             else
 31             {
 32                 int nq=++mem;par[nq]=par[q];par[q]=par[np]=nq;
 33                 memcpy(trans[nq],trans[q],sizeof(trans[nq]));len[nq]=len[p]+1;
 34                 posl[nq]=posl[q];posr[nq]=posl[q]-(len[nq]-len[par[nq]])+1;posl[q]=posr[nq]-1;
 35                 for(;p&&trans[p][ch]==q;p=par[p])    trans[p][ch]=nq;
 36             }
 37         }
 38     }
 39     void build()
 40     {
 41         np=root=++mem;
 42         int i,now;
 43         for(i=1;i<=ll;i++)
 44         {
 45             append(s[i]-'a'),sss[np].insert(i);
 46             for(now=np;now!=root&&!posr[now]&&!posl[now];now=par[now])
 47             {
 48                 posl[now]=i-len[par[now]];posr[now]=i-len[now]+1;
 49             }
 50         }
 51     }
 52 }
 53 namespace ST
 54 {
 55     int ch[200100][26];
 56     using SAM::par;
 57     void build()
 58     {
 59         int i;
 60         for(i=1;i<=SAM::mem;i++)
 61         {
 62             if(par[i])
 63             {
 64                 ch[par[i]][s[SAM::posl[i]]-'a']=i;
 65             }
 66         }
 67     }
 68     /*
 69     void out()
 70     {
 71         int i,j,k;using SAM::len,SAM::posl,SAM::posr;
 72         for(i=1;i<=SAM::mem;i++)
 73         {
 74             for(j=0;j<26;j++)
 75             {
 76                 if(ch[i][j])
 77                 {
 78                     printf("%d %d ",i,ch[i][j]);
 79                     for(k=posl[ch[i][j]];k>=posr[ch[i][j]];k--)    putchar(s[k]);
 80                     puts("");
 81                 }
 82             }
 83         }
 84     }
 85     */
 86 }
 87 void work(int tt)
 88 {
 89     using SAM::root,SAM::posl,SAM::posr,ST::ch;
 90     int i,now=root,j,k;
 91     for(i=l2;i>=1;)
 92     {
 93         now=ch[now][ss[i]-'a'];
 94         if(!now)    return;
 95         for(j=i,k=posl[now];j>=1&&k>=posr[now];j--,k--)
 96             if(ss[j]!=s[k])
 97                 return;
 98         i-=posl[now]-posr[now]+1;
 99         //printf("b%d %d %d %d
",now,i,posl[now],posr[now]);
100     }
101     vv[now].push_back(tt);//printf("a%d
",now);
102 }
103 queue<int> q;int in[200100];
104 void work2()
105 {
106     using SAM::mem,SAM::par;
107     int i,j,t;vector<int> tmp;
108     for(i=1;i<=mem;i++)    if(par[i])    in[par[i]]++;
109     for(i=1;i<=mem;i++)    if(!in[i])    q.push(i);
110     while(!q.empty())
111     {
112         t=q.front();q.pop();
113         if(vv[t].size())
114         {
115             tmp.clear();
116             for(auto k:sss[t])    tmp.push_back(k);
117             //for(i=0;i<tmp.size();i++)    printf("%d ",tmp[i]);puts("");
118         }
119         for(auto p:vv[t])
120         {
121             for(i=0,j=x[p]-1;j<tmp.size();i++,j++)
122             {
123                 ans[p]=min(ans[p],tmp[j]-tmp[i]+lll[p]);
124             }
125         }
126         if(par[t])
127         {
128             if(sss[par[t]].size()<sss[t].size())    swap(sss[par[t]],sss[t]);
129             for(auto k:sss[t])    sss[par[t]].insert(k);
130             sss[t].clear();
131             in[par[t]]--;
132             if(!in[par[t]])    q.push(par[t]);
133         }
134     }
135 }
136 int main()
137 {
138     int i;
139     scanf("%s",s+1);ll=strlen(s+1);
140     SAM::build();ST::build();
141     //ST::out();return 0;
142     scanf("%d",&n);
143     for(i=1;i<=n;i++)
144     {
145         scanf("%d%s",&x[i],ss+1);l2=lll[i]=strlen(ss+1);
146         work(i);
147     }
148     memset(ans,0x3f,sizeof(ans));
149     work2();
150     for(i=1;i<=n;i++)
151         printf("%d
",ans[i]==0x3f3f3f3f?-1:ans[i]);
152     return 0;
153 }
View Code

还有一份看上去很高妙的bitset字符串匹配(不是自己写的,先记一下)

来源:http://codeforces.com/contest/963/submission/37784765

 1 #include<bits/stdc++.h>
 2 #define N 100005
 3 using namespace std;
 4 bitset<N> b[26],tmp;
 5 char s[N],t[N];
 6 int main(){
 7     scanf("%s",s);
 8     int n=strlen(s);
 9     for (int i=0;i<n;i++)
10         b[s[i]-'a'][i]=1;
11     int Q; scanf("%d",&Q);
12     while (Q--){
13         int k; scanf("%d%s",&k,t);
14         int m=strlen(t);
15         tmp.set();
16         for (int i=0;i<m;i++)
17             tmp&=b[t[i]-'a']>>i;
18         if (tmp.count()<k){
19             puts("-1");
20             continue;
21         }
22         vector<int> v;
23         for (int i=tmp._Find_first();i<n;i=tmp._Find_next(i))
24             v.push_back(i);
25         int ans=1e9;
26         for (int i=0;i+k-1<v.size();i++)
27             ans=min(ans,v[i+k-1]-v[i]+m);
28         printf("%d
",ans);
29     }
30 }
View Code

就是搞复杂了。。

要找一个字符串,只要在后缀自动机上一位一位找过去,保证最后到达的一定也是后缀树上的对应节点。。。

  1 #pragma GCC diagnostic error "-std=c++11"
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cstring>
  5 #include<set>
  6 #include<queue>
  7 using namespace std;
  8 typedef long long LL;
  9 char s[100010],ss[100100];
 10 int ll,x[100100],l2;
 11 int pp[100100];
 12 vector<int> vv[200100];
 13 set<int> sss[200100];
 14 int n,ans[100100];
 15 int lll[100100];
 16 int teststet;
 17 int ssss;
 18 
 19 namespace SAM
 20 {
 21     int mem,np,root;
 22     int len[200100],par[200100];
 23     int trans[200100][26];
 24     void append(int ch)
 25     {
 26         int p=np;np=++mem;len[np]=len[p]+1;
 27         for(;p&&!trans[p][ch];p=par[p])    trans[p][ch]=np;
 28         if(!p)    par[np]=root;
 29         else
 30         {
 31             int q=trans[p][ch];
 32             if(len[q]==len[p]+1)    par[np]=q;
 33             else
 34             {
 35                 int nq=++mem;par[nq]=par[q];par[q]=par[np]=nq;
 36                 memcpy(trans[nq],trans[q],sizeof(trans[nq]));len[nq]=len[p]+1;
 37                 for(;p&&trans[p][ch]==q;p=par[p])    trans[p][ch]=nq;
 38             }
 39         }
 40     }
 41     void build()
 42     {
 43         np=root=++mem;
 44         int i;
 45         for(i=1;i<=ll;i++)
 46         {
 47             append(s[i]-'a'),sss[np].insert(i);
 48         }
 49     }
 50 }
 51 void work(int tt)
 52 {
 53     using SAM::trans;
 54     int i,now=SAM::root;
 55     for(i=1;i<=l2;i++)
 56     {
 57         now=trans[now][ss[i]-'a'];
 58     }
 59     vv[now].push_back(tt);
 60 }
 61 queue<int> q;int in[200100];
 62 void work2()
 63 {
 64     using SAM::mem;using SAM::par;
 65     int i,j,t;vector<int> tmp;
 66     for(i=1;i<=mem;i++)    if(par[i])    in[par[i]]++;
 67     for(i=1;i<=mem;i++)    if(!in[i])    q.push(i);
 68     while(!q.empty())
 69     {
 70         t=q.front();q.pop();
 71         if(vv[t].size())
 72         {
 73             tmp.clear();
 74             for(auto k:sss[t])    tmp.push_back(k);
 75         }
 76         for(auto p:vv[t])
 77         {
 78             for(i=0,j=x[p]-1;j<tmp.size();i++,j++)
 79             {
 80                 ans[p]=min(ans[p],tmp[j]-tmp[i]+lll[p]);
 81             }
 82         }
 83         if(par[t])
 84         {
 85             if(sss[par[t]].size()<sss[t].size())    swap(sss[par[t]],sss[t]);
 86             for(auto k:sss[t])    sss[par[t]].insert(k);
 87             sss[t].clear();
 88             in[par[t]]--;
 89             if(!in[par[t]])    q.push(par[t]);
 90         }
 91     }
 92 }
 93 int main()
 94 {
 95     int i;
 96     scanf("%s",s+1);ll=strlen(s+1);
 97     SAM::build();
 98     scanf("%d",&n);
 99     for(i=1;i<=n;i++)
100     {
101         scanf("%d%s",&x[i],ss+1);l2=lll[i]=strlen(ss+1);
102         work(i);
103     }
104     int aefsaf;
105     memset(ans,0x3f,sizeof(ans));
106     work2();
107     for(i=1;i<=n;i++)
108         printf("%d
",ans[i]==0x3f3f3f3f?-1:ans[i]);
109     return 0;
110 }
View Code
原文地址:https://www.cnblogs.com/hehe54321/p/8994810.html