[NOI2011]阿狸的打字机 [AC自动机+树状数组]

2024-01-30 01:58

本文主要是介绍[NOI2011]阿狸的打字机 [AC自动机+树状数组],希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

传送门

考虑暴力, 就是将所有为y的fail并且以x结束的点

如果在fail树上考虑呢?

我们发现y到根经过的所有点, 对应到自动机上就是将所有y的fail节点跳一边

如果我们将它们+1, 然后查询子树和, 就相当于在自动机上, 能跳到x的点的个数

我们在fail树上dfs, 显然到了结束的节点就将某一个子串遍历完了, 如果我们把这个子串到根的路径都加1, 那么x在fail树上的子树和

就是x的答案.

然后dfs序+树状数组就可以了


#include<bits/stdc++.h>
#define N 200050
using namespace std;
char s[N];
int n,tot,num,pos[N],ans[N];
int x[N],y[N];
vector<pair<int, int> > v[N];
int ch[N][26], fa[N], fail[N], p[N];
vector<int> son[N]; 
int first[N], nxt[N], to[N], ret;
void add(int x,int y){ nxt[++ret] = first[x], first[x] = ret, to[ret] = y;}
int st[N],ed[N],sign;
int c[N]; 
void Modify(int x,int val){ for(;x<=sign;x+=x&-x) c[x] += val;}
int Quary(int x){int ans=0; for(;x;x-=x&-x) ans += c[x]; return ans;}
void Build(){queue<int> q;for(int i=0;i<26;i++)if(ch[0][i]) q.push(ch[0][i]);while(!q.empty()){int x = q.front(); q.pop();for(int i=0;i<26;i++){int j = fail[x];if(ch[x][i]){ fail[ch[x][i]] = ch[j][i]; q.push(ch[x][i]);}else ch[x][i] = ch[j][i];}}
}
void dfs(int u){st[u] = ++sign;for(int i=first[u];i;i=nxt[i]){int t=to[i]; dfs(t);} ed[u] = sign;
}
void calc(int u){Modify(st[u], 1);int Siz = v[pos[u]].size();if(Siz){ for(int i=0;i<Siz;i++){ int x = v[pos[u]][i].first, id = v[pos[u]][i].second;ans[id] = Quary(ed[p[x]]) - Quary(st[p[x]]-1);} }for(int i=0;i<son[u].size();i++){int t=son[u][i]; calc(t);} Modify(st[u],-1);
}
int main(){scanf("%s%d",s,&n);int len = strlen(s), now = 0;for(int i=0;i<len;i++){if(s[i] >= 'a' && s[i] <= 'z'){int x = s[i] - 'a';if(!ch[now][x]) ch[now][x] = ++tot, fa[ch[now][x]] = now;now = ch[now][x];}if(s[i] == 'P') pos[now] = ++num, p[num] = now;if(s[i] == 'B') now = fa[now];} for(int i=0;i<=tot;i++)for(int j=0;j<26;j++)if(ch[i][j]) son[i].push_back(ch[i][j]);Build();for(int i=1;i<=tot;i++) add(fail[i], i);dfs(0);for(int i=1;i<=n;i++){scanf("%d%d",&x[i],&y[i]);v[y[i]].push_back(make_pair(x[i],i));} calc(0);for(int i=1;i<=n;i++) printf("%d\n",ans[i]); return 0;
} 

 

这篇关于[NOI2011]阿狸的打字机 [AC自动机+树状数组]的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/658777

相关文章

hdu2241(二分+合并数组)

题意:判断是否存在a+b+c = x,a,b,c分别属于集合A,B,C 如果用暴力会超时,所以这里用到了数组合并,将b,c数组合并成d,d数组存的是b,c数组元素的和,然后对d数组进行二分就可以了 代码如下(附注释): #include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<que

hdu 1166 敌兵布阵(树状数组 or 线段树)

题意是求一个线段的和,在线段上可以进行加减的修改。 树状数组的模板题。 代码: #include <stdio.h>#include <string.h>const int maxn = 50000 + 1;int c[maxn];int n;int lowbit(int x){return x & -x;}void add(int x, int num){while

hdu 3065 AC自动机 匹配串编号以及出现次数

题意: 仍旧是天朝语题。 Input 第一行,一个整数N(1<=N<=1000),表示病毒特征码的个数。 接下来N行,每行表示一个病毒特征码,特征码字符串长度在1—50之间,并且只包含“英文大写字符”。任意两个病毒特征码,不会完全相同。 在这之后一行,表示“万恶之源”网站源码,源码字符串长度在2000000之内。字符串中字符都是ASCII码可见字符(不包括回车)。

POJ 1625 自动机

给出包含n个可见字符的字符集,以下所提字符串均由该字符集中的字符构成。给出p个长度不超过10的字符串,求长为m且不包含上述p个字符串的字符串有多少个。 g++提交 int mat[108][108] ;int matn ;int N ;map<char ,int> to ;//ACconst int maxm = 108 ;const int kin

zoj 3228 ac自动机

给出一个字符串和若干个单词,问这些单词在字符串里面出现了多少次。单词前面为0表示这个单词可重叠出现,1为不可重叠出现。 Sample Input ab 2 0 ab 1 ab abababac 2 0 aba 1 aba abcdefghijklmnopqrstuvwxyz 3 0 abc 1 def 1 jmn Sample Output Case 1 1 1 Case 2

D4代码AC集

贪心问题解决的步骤: (局部贪心能导致全局贪心)    1.确定贪心策略    2.验证贪心策略是否正确 排队接水 #include<bits/stdc++.h>using namespace std;int main(){int w,n,a[32000];cin>>w>>n;for(int i=1;i<=n;i++){cin>>a[i];}sort(a+1,a+n+1);int i=1

C语言:柔性数组

数组定义 柔性数组 err int arr[0] = {0}; // ERROR 柔性数组 // 常见struct Test{int len;char arr[1024];} // 柔性数组struct Test{int len;char arr[0];}struct Test *t;t = malloc(sizeof(Test) + 11);strcpy(t->arr,

C 语言基础之数组

文章目录 什么是数组数组变量的声明多维数组 什么是数组 数组,顾名思义,就是一组数。 假如班上有 30 个同学,让你编程统计每个人的分数,求最高分、最低分、平均分等。如果不知道数组,你只能这样写代码: int ZhangSan_score = 95;int LiSi_score = 90;......int LiuDong_score = 100;int Zhou

计算数组的斜率,偏移,R2

模拟Excel中的R2的计算。         public bool fnCheckRear_R2(List<double[]> lRear, int iMinRear, int iMaxRear, ref double dR2)         {             bool bResult = true;             int n = 0;             dou

C# double[] 和Matlab数组MWArray[]转换

C# double[] 转换成MWArray[], 直接赋值就行             MWNumericArray[] ma = new MWNumericArray[4];             double[] dT = new double[] { 0 };             double[] dT1 = new double[] { 0,2 };