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’开始查找字符串里是否存在,如果存在 ...
随机推荐
- VB程序逆向反汇编常见的函数(修改版)
VB程序逆向常用的函数 1) 数据类型转换: a) __vbaI2Str 将一个字符串转为8 位(1个字节)的数值形式(范围在 0 至 255 之间) 或2 个字节的数值形式(范围在 -32,7 ...
- 一处折腾笔记:Android内嵌html5加入原生微信分享的解决的方法
有一段时间没有瞎折腾了. 这周一刚上班萌主过来反映说:微信里面打开聚客宝.分享功能是能够的(这里是用微信自身的js-sdk实现的).可是在android应用里面打开点击就没反应了:接下来狡猾的丁丁在产 ...
- GoodUI:页面布局的技巧和设计理念
http://goodui.org/ 中文翻译:http://www.cnblogs.com/Wayou/p/goodui.html 一年了,小小少年从幼年期过渡到成长期要开始加速冲刺了.毕竟钻头就是 ...
- java语法基础(四)
继承 继承概述 继承是面向对象语言的三大基本特性(封装,继承,多态)之一. 一个类可以继承另外一个类,继承的类称为子类(也可以叫派生类),被继承的类称为父类(或者也叫基类,超类). 通过继承,子类可以 ...
- Lightoj 1016 - Brush (II)
After the long contest, Samee returned home and got angry after seeing his room dusty. Who likes to ...
- HDU3001 Travelling —— 状压DP(三进制)
题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=3001 Travelling Time Limit: 6000/3000 MS (Java/ ...
- 【HDU 1561】 The More,The better
[题目链接] 点击打开链接 [算法] 树形背包 注意是一棵森林 [代码] #include<bits/stdc++.h> using namespace std; #define MAXN ...
- .NET MVC API返回JSON对象
方法多种,自己目前采用的是自定义返回格式的方法,不需要修改配置文件. 辅助类: public class ApiResponseHelper { public static HttpResponseM ...
- Ajax 异步查询 ,刷新页面的一部分
调用的过程是,通过Jquery注册单击事件,当单击分部视图中的按钮,就取得分部视图中文本框的值,然后调用$.Get()函数以Get形式调用控制器SearchPeople方法,参数为searchText ...
- Mysql数据库的用户和日志管理
Mysql数据库的用户和日志管理 数据库的用户管理 1.mysql用户账号管理 用户账号 user@host user:账户名称 host:此账户可通过哪些客户端主机请求创建连接线程,可以是ip.主机 ...