嗯---NOI水题集合之:阿狸的打字机

阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机。打字机 上只有 28 个按键,分别印有 26 个小写英文字母和‘B‘、‘P‘两个字母。 经阿狸研究发现,这个打字机是这样工作的:

? 输入小写字母,打字机的一个凹槽中会加入这个字母(按 P 前凹槽中至 少有一个字母)。

? 按一下印有‘B‘的按键,打字机凹槽中最后一个字母会消失。

? 按一下印有‘P‘的按键,打字机会在纸上打印出凹槽中现有的所有字母并 换行,但凹槽中的字母不会消失(保证凹槽中至少有一个字母)。

例如,阿狸输入 aPaPBbP,纸上被打印的字符如下: a aa ab 我们把纸上打印出来的字符串从 1 开始顺序编号,一直到 n。打字机有一个 非常有趣的功能,在打字机中暗藏一个带数字的小键盘,在小键盘上输入两个数 (x,y)(其中 1≤x,y≤n),打字机会显示第 x 个打印的字符串在第 y 个打印的字符串 中出现了多少次。 阿狸发现了这个功能以后很兴奋,他想写个程序完成同样的功能,你能帮助 他么?

 

输入的第一行包含一个字符串,按阿狸的输入顺序给出所有阿狸输入的字符。 第二行包含一个整数 m,表示询问个数。 接下来 m 行描述所有由小键盘输入的询问。其中第 i 行包含两个整数 x, y, 表示第 i 个询问为(x, y)。

输出 m 行,其中第 i 行包含一个整数,表示第 i 个询问的答案。 

样例输入

aPaPBbP

3

1 2

1 3

2 3

样例输出

2

1

看了好一会儿,。。。最终才发现是fail树上的区间询问。。原来想成了链剖。

fail树上一个点的父节点一直到根都是他的后缀,所以只要一个点x在fail树上的点y的子树内,x就包含y,所以查询a在b里出现了多少次

就是查询y的所有前缀在trie中代表的点在fail树上的对应点有多少在x的对应点的子树内。

先用一个栈快速建出包含所有P出来的串的一颗trie,然后直接getfail建出fail树。

然后dfs,依照dfs序把子树放到区间上。

然后把询问离线,注意fail树和trie树上的点以及询问的对应关系。。这个让我挂了好久。。最好让fail树和trie数上的同一个点用同一个数表示(数组下标嘛)

最后一遍dfs.遇到一个点就把他在线段树上加1.退出的时候就把这个点减1.如果这个点是一个‘b’点,就查询答案。

就是线段树单点修改,区间查询。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<stack>
  4 #include<queue>
  5 #include<cstring>
  6 using namespace std;
  7 #define maxn 200000
  8 struct seg_node{
  9     int l;
 10     int r;
 11     int val;
 12     seg_node* left;
 13     seg_node* right;
 14 }zqq[maxn];
 15 seg_node* root1;
 16 int ctot = 0;
 17 inline void update(seg_node* x){
 18     x->val = x->left->val + x->right->val;
 19 }
 20 seg_node* build(int l,int r){
 21     seg_node* cur = &zqq[++ctot];
 22     cur->l = l;
 23     cur->r = r;
 24     cur->val = 0;
 25     if(l == r){
 26         return cur;
 27     }
 28     int mid = (l+r) >>1;
 29     cur->left= build(l,mid);
 30     cur->right = build(mid+1,r);
 31     return cur;
 32 }
 33 void modify(seg_node* cur,int pos,int va){
 34     if(cur->l == cur->r){
 35         cur->val = va;
 36         return;
 37     }
 38     int mid = (cur->l+cur->r) >>1;
 39     if(pos <= mid){
 40         modify(cur->left,pos,va);
 41     }
 42     else{
 43         modify(cur->right,pos,va);
 44     }
 45     update(cur);
 46 }
 47 int find(seg_node* cur,int l,int r){
 48     if(cur->l == l && cur->r == r){
 49         return cur->val;
 50     }
 51     int mid =(cur->l+cur->r) >>1;
 52     if(r <= mid){
 53         return find(cur->left,l,r);
 54     }
 55     else if(l > mid){
 56         return find(cur->right,l,r);
 57     }
 58     else{
 59         return find(cur->left,l,mid) + find(cur->right,mid+1,r);
 60     }
 61 }
 62 struct edge{
 63     int np;
 64     int next;
 65 }h[maxn*3];
 66 int tot = 1;
 67 int head[maxn];
 68 void add(int x,int y){
 69     h[++tot] = (edge){y,head[x]};
 70     head[x] = tot;
 71 }
 72 struct node{
 73     int next[30];
 74     vector<pair<int,int> > lxl;
 75     int fail;
 76     int count;
 77 }e[maxn];
 78 int cnt = 0;
 79 stack<int> st;
 80 int m;
 81 int len;
 82 char s[maxn];
 83 int root = 0;
 84 queue<int> q;
 85 void getfail(){
 86     q.push(root);
 87     int now,cur,f;
 88     e[root].fail = -1;
 89     while(!q.empty()){
 90         now = q.front();
 91         q.pop();
 92         if(now == root){
 93             for(int i = 0;i<27;i++){
 94                 if(e[now].next[i]){
 95                     e[e[now].next[i]].fail = root;
 96                     add(root,e[now].next[i]);
 97                     q.push(e[now].next[i]);
 98                 }
 99             }
100             continue;
101         }
102         for(int i = 0;i<27;i++){
103             f = e[now].fail;
104             if(e[now].next[i]){
105                 cur = e[now].next[i];
106                 while(f != -1 && !e[f].next[i]){
107                     f = e[f].fail;
108                 }
109                 if(f == -1){
110                     e[cur].fail = root;
111                     add(root,cur);
112                 }
113                 else{
114                     e[cur].fail = e[f].next[i];
115                     add(e[f].next[i],cur);
116                 }
117                 q.push(cur);
118             }
119         }
120     }
121 }
122 struct zqq{
123     int x,y,ans;
124 }qs[maxn];
125 int qq[maxn];
126 int ccnt =0;
127 int li[maxn];
128 int ri[maxn];
129 int idx = 0;
130 void dfs(int x){
131     li[x] = ++idx;
132     for(int ne = head[x];ne;ne = h[ne].next){
133         dfs(h[ne].np);
134     }
135     ri[x] = idx;
136 }
137 void dfs1(int x){
138     if(x == 8){
139         int lxlgay = 111;
140     }
141     modify(root1,li[x],1);
142     int cur;
143     int nowy;
144     int nowid;
145     for(int i =0;i<e[x].lxl.size();i++){
146         nowy = e[x].lxl[i].first;
147         nowid = e[x].lxl[i].second;
148         qs[nowid].ans = find(root1,li[qq[nowy]],ri[qq[nowy]]);
149     }
150     for(int i = 0;i<27;i++){
151         if(e[x].next[i]){
152             cur = e[x].next[i];
153             dfs1(cur);
154         }
155     }
156     modify(root1,li[x],0);
157 }
158 int a1,a2;
159 int main(){
160     scanf("%s",s);
161     len = strlen(s);
162     st.push(root);
163     int now;
164     for(int i = 0;i<len;i++){
165         if(s[i] == ‘B‘){
166             st.pop();
167         }
168         else if(s[i] == ‘P‘){
169             ccnt++;
170             qq[ccnt] = st.top();
171         }
172         else{
173             now = st.top();
174             if(!e[now].next[s[i]-‘a‘]){
175                 cnt++;
176                 e[now].next[s[i]-‘a‘] = cnt;
177                 st.push(cnt);
178             }
179             else{
180                 st.push(e[now].next[s[i]-‘a‘]);
181             }
182         }
183     }
184     getfail();
185     dfs(root);
186     scanf("%d",&m);
187     for(int i = 1;i<=m;i++){
188         scanf("%d %d",&a1,&a2);
189         qs[i].x = a1;
190         qs[i].y = a2;
191         e[qq[a2]].lxl.push_back(pair<int,int>(a1,i));
192     }
193     root1 = build(1,idx);
194     dfs1(root);
195     for(int i = 1;i<=m;i++){
196         printf("%d\n",qs[i].ans);
197     }
198     return 0;
199 }
时间: 2024-10-06 10:59:57

嗯---NOI水题集合之:阿狸的打字机的相关文章

洛谷数论{水题}集合

1. P1327数列排序 题目描述 给定一个数列{an},这个数列满足ai≠aj(i≠j),现在要求你把这个数列从小到大排序,每次允许你交换其中任意一对数,请问最少需要几次交换? 输入输出格式 输入格式: 第一行,正整数n (n<=100,000). 以下若干行,一共n个数,用空格分隔开,表示数列{an},任意-231<ai<231. 输出格式: 只有一行,包含一个数,表示最少的交换次数. 输入输出样例 输入样例#1: 8 8 23 4 16 77 -5 53 100 输出样例#1: 5

hdu 2561~2566 水题集合

2561: 1 #include <iostream> 2 #include <cstring> 3 using namespace std; 4 5 const int N = 10; 6 int num[N]; 7 8 int main() 9 { 10 int t; 11 cin >> t; 12 while ( t-- ) 13 { 14 int n; 15 cin >> n; 16 for ( int i = 0; i < n; i++ )

[ZPG TEST 114] 阿狸的英文名【水题】

1.      阿狸的英文名 阿狸最近想起一个英文名,于是他在网上查了很多个名字.他发现一些名字可以由两个不同的名字各取一部分得来,例如John(约翰)的前缀 "John"和Robinson(鲁滨逊)的后缀 "son" 连在一起就是Johnson. 现在他找到了两个喜欢的名字(名字可看作字符串),用A和B表示,他想知道取A的一个非空前缀和B的一个非空后缀,连接在一起能组成多少不同的字符串. 输入格式 输入两行,分别表示字符串A和B:字符串只包含小写英文字母. 输出格

【转载】POJ水题大集合

POJ水题大集合 poj1000:A+B problempoj1002:电话上按键对应着数字.现在给n个电话,求排序.相同的归一类poj1003:求最小的n让1+1/2+1/3+...+1/n大于给的一个实数poj1004:求一堆实数的平均数poj1005:由坐标 (0,0) 开始,以半圆为形状每年侵蚀50m^2,问(0,0)开始到(x,y)结束需要多长时间poj1006:三个周期是常数.现在给三个周期出现高峰的时候,问下一次出现高峰是什么时候poj1007:求字符串排序poj1008:一种日历

4.7-4.9补题+水题+高维前缀和

题目链接:51nod 1718 Cos的多项式  [数学] 题解: 2cosx=2cosx 2cos2x=(2cosx)^2-2 2cos3x=(2cosx)^3-3*(2cosx) 数归证明2cos(nx)能表示成关于2cosx的多项式,设为f(n) f(1)=x,f(2)=x^2-2(其中的x就是2cosx) 假设n=1~k时均成立(k>=3) 当n=k+1时 由cos((k+1)x)=cos(kx)cos(x)-sin(kx)sin(x) cos((k-1)x)=cos(kx)cos(x)

#82. 【UR #7】水题生成器

链接:http://uoj.ac/problem/82 今天是世界水日,著名的水题资源专家蝈蝈大臣向世界宣布了他的一项新发明 -- 水题生成器. 每道题目都有一个正整数的难度值.水题生成器虽然强大但是功能有限.水题生成器内部有一个参数 nn,你可以告诉水题生成器一个能整除 n!n! 的正整数 dd,水题生成器就会产生一道难度值恰为 dd 的水题.这里 n!n! 表示 nn 的阶乘. 现在蝈蝈大臣的助手欧姆想用水题生成器产生不超过 nn 道水题,且难度值之和恰为 mm.保证 1≤m≤n!1≤m≤n

UVa 1595 (水题) Symmetry

颓废的一个下午,一直在切水题,(ˉ▽ ̄-) 首先如果这些点是对称的话,那么它们的对称轴就是x = m,m是横坐标的平均值. 把这些点放到一个集合里,然后扫描每个点,计算出它关于x = m的对称点,看这个点是否在集合里面. 如果有一个不在的话,说明不能构成对称图形. 1 #include <cstdio> 2 #include <algorithm> 3 #include <set> 4 using namespace std; 5 6 struct Point 7 {

2015南阳CCPC L - Huatuo&#39;s Medicine 水题

L - Huatuo's Medicine Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 无 Description Huatuo was a famous doctor. He use identical bottles to carry the medicine. There are different types of medicine. Huatuo put medicines into the bottles and chain these b

sdut 2841 Bit Problem (水题)

题目 贴这个题是因为看题解有更简单的方法, 我做的时候是直接算的, 也很简单. 贴一下题解吧: 如果一个整数不等于 0,那么该整数的二进制表示中至少有一位是 1. 这个题结果可以直接输出 x - (x&(x-1)); 因为x-1 之后二进制下,就是最右边的1变成了0, 最右边的1的 右边所有的0变成了1, 不影响最左边. 我的代码: 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4