Frequency of String CodeForces - 963D
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了)
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<set>
#include<queue>
using namespace std;
typedef long long LL;
char s[],ss[];
int ll,x[],l2;
int pp[];
vector<int> vv[];
set<int> sss[];
int n,ans[];
int lll[];
namespace SAM
{
int mem,np,root;
int len[],par[];
int trans[][];
int posl[],posr[];
void append(int ch)
{
int p=np;np=++mem;len[np]=len[p]+;
for(;p&&!trans[p][ch];p=par[p]) trans[p][ch]=np;
if(!p) par[np]=root;
else
{
int q=trans[p][ch];
if(len[q]==len[p]+) par[np]=q;
else
{
int nq=++mem;par[nq]=par[q];par[q]=par[np]=nq;
memcpy(trans[nq],trans[q],sizeof(trans[nq]));len[nq]=len[p]+;
for(;p&&trans[p][ch]==q;p=par[p]) trans[p][ch]=nq;
}
}
}
void build()
{
np=root=++mem;
int i,now;
for(i=;i<=ll;i++) append(s[i]-'a'),pp[i]=np,sss[np].insert(i);
for(i=;i<=ll;i++)
{
for(now=pp[i];now!=root&&!posr[now]&&!posl[now];now=par[now])
{
posl[now]=i-len[par[now]];posr[now]=i-len[now]+;
}
}
}
}
namespace ST
{
int ch[][];
using SAM::par;
void build()
{
int i;
for(i=;i<=SAM::mem;i++)
{
if(par[i])
{
ch[par[i]][s[SAM::posl[i]]-'a']=i;
}
}
}
/*
void out()
{
int i,j,k;using SAM::len,SAM::posl,SAM::posr;
for(i=1;i<=SAM::mem;i++)
{
for(j=0;j<26;j++)
{
if(ch[i][j])
{
printf("%d %d ",i,ch[i][j]);
for(k=posl[ch[i][j]];k>=posr[ch[i][j]];k--) putchar(s[k]);
puts("");
}
}
}
}
*/
}
void work(int tt)
{
using SAM::root,SAM::posl,SAM::posr,ST::ch;
int i,now=root,j,k;
for(i=l2;i>=;)
{
now=ch[now][ss[i]-'a'];
if(!now) return;
for(j=i,k=posl[now];j>=&&k>=posr[now];j--,k--)
if(ss[j]!=s[k])
return;
i-=posl[now]-posr[now]+;
//printf("b%d %d %d %d\n",now,i,posl[now],posr[now]);
}
vv[now].push_back(tt);//printf("a%d\n",now);
}
queue<int> q;int in[];
void work2()
{
using SAM::mem,SAM::par;
int i,j,t,l,r;vector<int> tmp;
for(i=;i<=mem;i++) if(par[i]) in[par[i]]++;
for(i=;i<=mem;i++) if(!in[i]) q.push(i);
while(!q.empty())
{
t=q.front();q.pop();
if(vv[t].size())
{
tmp.clear();
for(auto k:sss[t]) tmp.push_back(k);
//for(i=0;i<tmp.size();i++) printf("%d ",tmp[i]);puts("");
}
for(auto p:vv[t])
{
for(i=,j=x[p]-;j<tmp.size();i++,j++)
{
ans[p]=min(ans[p],tmp[j]-tmp[i]+lll[p]);
}
}
if(par[t])
{
if(sss[par[t]].size()<sss[t].size()) swap(sss[par[t]],sss[t]);
for(auto k:sss[t]) sss[par[t]].insert(k);
sss[t].clear();
in[par[t]]--;
if(!in[par[t]]) q.push(par[t]);
}
}
}
int main()
{
int i;
scanf("%s",s+);ll=strlen(s+);
SAM::build();ST::build();
//ST::out();return 0;
scanf("%d",&n);
for(i=;i<=n;i++)
{
scanf("%d%s",&x[i],ss+);l2=lll[i]=strlen(ss+);
work(i);
}
memset(ans,0x3f,sizeof(ans));
work2();
for(i=;i<=n;i++)
printf("%d\n",ans[i]==0x3f3f3f3f?-:ans[i]);
return ;
}
代码2:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<set>
#include<queue>
using namespace std;
typedef long long LL;
char s[],ss[];
int ll,x[],l2;
int pp[];
vector<int> vv[];
set<int> sss[];
int n,ans[];
int lll[];
namespace SAM
{
int mem,np,root;
int len[],par[];
int trans[][];
int posl[],posr[];
void append(int ch)
{
int p=np;np=++mem;len[np]=len[p]+;
for(;p&&!trans[p][ch];p=par[p]) trans[p][ch]=np;
if(!p) par[np]=root;
else
{
int q=trans[p][ch];
if(len[q]==len[p]+) par[np]=q;
else
{
int nq=++mem;par[nq]=par[q];par[q]=par[np]=nq;
memcpy(trans[nq],trans[q],sizeof(trans[nq]));len[nq]=len[p]+;
posl[nq]=posl[q];posr[nq]=posl[q]-(len[nq]-len[par[nq]])+;posl[q]=posr[nq]-;
for(;p&&trans[p][ch]==q;p=par[p]) trans[p][ch]=nq;
}
}
}
void build()
{
np=root=++mem;
int i,now;
for(i=;i<=ll;i++)
{
append(s[i]-'a'),sss[np].insert(i);
for(now=np;now!=root&&!posr[now]&&!posl[now];now=par[now])
{
posl[now]=i-len[par[now]];posr[now]=i-len[now]+;
}
}
}
}
namespace ST
{
int ch[][];
using SAM::par;
void build()
{
int i;
for(i=;i<=SAM::mem;i++)
{
if(par[i])
{
ch[par[i]][s[SAM::posl[i]]-'a']=i;
}
}
}
/*
void out()
{
int i,j,k;using SAM::len,SAM::posl,SAM::posr;
for(i=1;i<=SAM::mem;i++)
{
for(j=0;j<26;j++)
{
if(ch[i][j])
{
printf("%d %d ",i,ch[i][j]);
for(k=posl[ch[i][j]];k>=posr[ch[i][j]];k--) putchar(s[k]);
puts("");
}
}
}
}
*/
}
void work(int tt)
{
using SAM::root,SAM::posl,SAM::posr,ST::ch;
int i,now=root,j,k;
for(i=l2;i>=;)
{
now=ch[now][ss[i]-'a'];
if(!now) return;
for(j=i,k=posl[now];j>=&&k>=posr[now];j--,k--)
if(ss[j]!=s[k])
return;
i-=posl[now]-posr[now]+;
//printf("b%d %d %d %d\n",now,i,posl[now],posr[now]);
}
vv[now].push_back(tt);//printf("a%d\n",now);
}
queue<int> q;int in[];
void work2()
{
using SAM::mem,SAM::par;
int i,j,t;vector<int> tmp;
for(i=;i<=mem;i++) if(par[i]) in[par[i]]++;
for(i=;i<=mem;i++) if(!in[i]) q.push(i);
while(!q.empty())
{
t=q.front();q.pop();
if(vv[t].size())
{
tmp.clear();
for(auto k:sss[t]) tmp.push_back(k);
//for(i=0;i<tmp.size();i++) printf("%d ",tmp[i]);puts("");
}
for(auto p:vv[t])
{
for(i=,j=x[p]-;j<tmp.size();i++,j++)
{
ans[p]=min(ans[p],tmp[j]-tmp[i]+lll[p]);
}
}
if(par[t])
{
if(sss[par[t]].size()<sss[t].size()) swap(sss[par[t]],sss[t]);
for(auto k:sss[t]) sss[par[t]].insert(k);
sss[t].clear();
in[par[t]]--;
if(!in[par[t]]) q.push(par[t]);
}
}
}
int main()
{
int i;
scanf("%s",s+);ll=strlen(s+);
SAM::build();ST::build();
//ST::out();return 0;
scanf("%d",&n);
for(i=;i<=n;i++)
{
scanf("%d%s",&x[i],ss+);l2=lll[i]=strlen(ss+);
work(i);
}
memset(ans,0x3f,sizeof(ans));
work2();
for(i=;i<=n;i++)
printf("%d\n",ans[i]==0x3f3f3f3f?-:ans[i]);
return ;
}
还有一份看上去很高妙的bitset字符串匹配(不是自己写的,先记一下)
来源:http://codeforces.com/contest/963/submission/37784765
#include<bits/stdc++.h>
#define N 100005
using namespace std;
bitset<N> b[],tmp;
char s[N],t[N];
int main(){
scanf("%s",s);
int n=strlen(s);
for (int i=;i<n;i++)
b[s[i]-'a'][i]=;
int Q; scanf("%d",&Q);
while (Q--){
int k; scanf("%d%s",&k,t);
int m=strlen(t);
tmp.set();
for (int i=;i<m;i++)
tmp&=b[t[i]-'a']>>i;
if (tmp.count()<k){
puts("-1");
continue;
}
vector<int> v;
for (int i=tmp._Find_first();i<n;i=tmp._Find_next(i))
v.push_back(i);
int ans=1e9;
for (int i=;i+k-<v.size();i++)
ans=min(ans,v[i+k-]-v[i]+m);
printf("%d\n",ans);
}
}
就是搞复杂了。。
要找一个字符串,只要在后缀自动机上一位一位找过去,保证最后到达的一定也是后缀树上的对应节点。。。
#pragma GCC diagnostic error "-std=c++11"
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<set>
#include<queue>
using namespace std;
typedef long long LL;
char s[],ss[];
int ll,x[],l2;
int pp[];
vector<int> vv[];
set<int> sss[];
int n,ans[];
int lll[];
int teststet;
int ssss; namespace SAM
{
int mem,np,root;
int len[],par[];
int trans[][];
void append(int ch)
{
int p=np;np=++mem;len[np]=len[p]+;
for(;p&&!trans[p][ch];p=par[p]) trans[p][ch]=np;
if(!p) par[np]=root;
else
{
int q=trans[p][ch];
if(len[q]==len[p]+) par[np]=q;
else
{
int nq=++mem;par[nq]=par[q];par[q]=par[np]=nq;
memcpy(trans[nq],trans[q],sizeof(trans[nq]));len[nq]=len[p]+;
for(;p&&trans[p][ch]==q;p=par[p]) trans[p][ch]=nq;
}
}
}
void build()
{
np=root=++mem;
int i;
for(i=;i<=ll;i++)
{
append(s[i]-'a'),sss[np].insert(i);
}
}
}
void work(int tt)
{
using SAM::trans;
int i,now=SAM::root;
for(i=;i<=l2;i++)
{
now=trans[now][ss[i]-'a'];
}
vv[now].push_back(tt);
}
queue<int> q;int in[];
void work2()
{
using SAM::mem;using SAM::par;
int i,j,t;vector<int> tmp;
for(i=;i<=mem;i++) if(par[i]) in[par[i]]++;
for(i=;i<=mem;i++) if(!in[i]) q.push(i);
while(!q.empty())
{
t=q.front();q.pop();
if(vv[t].size())
{
tmp.clear();
for(auto k:sss[t]) tmp.push_back(k);
}
for(auto p:vv[t])
{
for(i=,j=x[p]-;j<tmp.size();i++,j++)
{
ans[p]=min(ans[p],tmp[j]-tmp[i]+lll[p]);
}
}
if(par[t])
{
if(sss[par[t]].size()<sss[t].size()) swap(sss[par[t]],sss[t]);
for(auto k:sss[t]) sss[par[t]].insert(k);
sss[t].clear();
in[par[t]]--;
if(!in[par[t]]) q.push(par[t]);
}
}
}
int main()
{
int i;
scanf("%s",s+);ll=strlen(s+);
SAM::build();
scanf("%d",&n);
for(i=;i<=n;i++)
{
scanf("%d%s",&x[i],ss+);l2=lll[i]=strlen(ss+);
work(i);
}
int aefsaf;
memset(ans,0x3f,sizeof(ans));
work2();
for(i=;i<=n;i++)
printf("%d\n",ans[i]==0x3f3f3f3f?-:ans[i]);
return ;
}
Frequency of String CodeForces - 963D的更多相关文章
- Minimal string CodeForces - 797C
Minimal string CodeForces - 797C 题意:有一个字符串s和空串t和u,每次操作可以将s的第一个字符取出并删除然后放到t的最后,或者将t的最后一个字符取出并删除然后放到u的 ...
- CodeForces - 963D:Frequency of String (bitset暴力搞)
You are given a string ss. You should answer nn queries. The ii-th query consists of integer kiki an ...
- Tinkoff Internship Warmup Round 2018 and Codeforces Round #475 (Div. 1)D. Frequency of String
题意:有一个串s,n个串模式串t,问s的子串中长度最小的包含t k次的长度是多少 题解:把所有t建ac自动机,把s在ac自动机上匹配.保存每个模式串在s中出现的位置.这里由于t两两不同最多只有xsqr ...
- D. Mahmoud and Ehab and the binary string Codeforces Round #435 (Div. 2)
http://codeforces.com/contest/862/problem/D 交互题 fflush(stdout) 调试: 先行给出结果,函数代替输入 #include <cstdio ...
- You Are Given a Decimal String... CodeForces - 1202B [简单dp][补题]
补一下codeforces前天教育场的题.当时只A了一道题. 大致题意: 定义一个x - y - counter :是一个加法计数器.初始值为0,之后可以任意选择+x或者+y而我们由每次累加结果的最后 ...
- Check the string CodeForces - 960A
A has a string consisting of some number of lowercase English letters 'a'. He gives it to his friend ...
- CF963D Frequency of String
https://codeforces.com/problemset/problem/123/D 题目大意 给一个字符串 \(s\),每次询问一个字符串 \(m_i\) 和一个正整数 \(k_i\),问 ...
- Median String CodeForces - 1144E
You are given two strings ss and tt, both consisting of exactly kk lowercase Latin letters, ss is le ...
- Minimal string CodeForces – 797C
题目链接 题目难度: 1700rating 题目类型:string+贪心+STL 题目思路: 由于题目要求的最终结果是字典序最小的那个字符串,那么我们从贪心的从’a’开始查找字符串里是否存在,如果存在 ...
随机推荐
- 学习swift从青铜到王者之swift枚举07
空枚举 //空枚举 enum SomeEnumeration { // enumeration definition goes here } 枚举基本类型 //枚举基本类型 enum CompassP ...
- 【APUE】进程间通信之管道
管道是UNIX系统IPC最古老形式,并且所有UNIX系统都提供此种通信机制.管道由下面两种局限性: 1)历史上,它们是半双工的(即数据只能在一个方向上流动) 2)它们只能在具有公共祖先的进程之间使用. ...
- centos6.5 (linux) 禁用模块 IPV6模块的方法
装完centos后,默认开启了一些模块.可是有些模块并非我们必须的.比方眼下尚未在中国普及的IPV6 怎样关闭IPV6呢 以下介绍的方法,也能够在关闭其它模块的时候使用 第一步: 查找模块名称 使用命 ...
- CodeForces 404 Marathon ( 浮点数取模 -- 模拟 )
B. Marathon time limit per test 1 second memory limit per test 256 megabytes input standard input ou ...
- 李洪强iOS开发之函数式 编程初窥
函数式 编程初窥 最近在学习Erlang和Python.Erlang是完全的函数式编程语言,Python语言是面向对象的语言,但是它的语法引入了大量的函数式编程思想.越研究越觉得函数式的编程思路可 ...
- 关于mybatis的 insert into select 命令未结束问题
关于mybatis的 insert into select 命令未结束问题,最后以为是sql写错了,可是,在plsql运行又没问题.最后还是解决这个问题. 是设置问题. ### Cause: java ...
- [IT新应用]brave浏览器
https://www.brave.com/about.html The web has become a different place. With the ad-tech ecosystem ou ...
- Java小白手记:SSH
以下内容只是一个小白菜鸟的理解和总结,目的仅在于梳理思路. 13年的时候,我就说要学JAVA,有个C++高手同事赞许地说:"嗯,不错,SSH..."我不禁肃然起敬.SSH!多么高大 ...
- Ubuntu18开启redis服务自启动
设置redis服务开机自启动. 1.创建配置文件夹 sudo mkdir /etc/redis sudo cp /usr/local/redis/redis.conf /etc/redis sudo ...
- Masonry 动画更新约束
前言 说到iOS自动布局,有很多的解决办法.有的人使用xib/storyboard自动布局,也有人使用frame来适配.对于前者,笔者并不喜欢,也不支持.对于后者,更是麻烦,到处计算高度.宽度等,千万 ...