BZOJ4943 [NOI2017] 蚯蚓

题目描述

蚯蚓幼儿园有nn 只蚯蚓。幼儿园园长神刀手为了管理方便,时常让这些蚯蚓们列队表演。

所有蚯蚓用从11 nn 的连续正整数编号。每只蚯蚓的长度可以用一个正整数表示,根据入园要求,所有蚯蚓的长度都不超过66 。神刀手希望这些蚯蚓排成若干个队伍,初始时,每只蚯蚓各自排成一个仅有一只蚯蚓的队伍,该蚯蚓既在队首,也在队尾。

神刀手将会依次进行mm 次操作,每个操作都是以下三种操作中的一种:

  1. 给出ii jj ,令ii 号蚯蚓与jj 号蚯蚓所在的两个队伍合并为一个队伍,具体来说,令jj 号蚯蚓紧挨在ii 号蚯蚓之后,其余蚯蚓保持队伍的前后关系不变。

  2. 给出ii ,令ii 号蚯蚓与紧挨其后的一只蚯蚓分离为两个队伍,具体来说,在分离之后,ii 号蚯蚓在其中一个队伍的队尾,原本紧挨其后的那一只蚯蚓在另一个队伍的队首,其余蚯蚓保持队伍的前后关系不变。

  3. 给出一个正整数kk 和一个长度至少为kk 的数字串ss ,对于ss 的每个长度为kk 的连续子串tt (这样的子串共有|s| - k + 1sk+1 个,其中|s|s ss 的长度),定义函数f(t)f(t) ,询问所有这些f(t)f(t) 乘积998244353998244353 取模后的结果。其中f(t)f(t) 的定义如下: 对于当前的蚯蚓队伍,定义某个蚯蚓的向后kk 数字串为:从该蚯蚓出发,沿队伍的向后方向,寻找最近的kk 只蚯蚓(包括其自身),将这些蚯蚓的长度视作字符连接而成的数字串;如果这样找到的蚯蚓不足kk只,则其没有向后kk 数字串。例如蚯蚓的队伍为1010 号蚯蚓在队首,其后是2222 号蚯蚓,其后是33 号蚯蚓(为队尾),这些蚯蚓的长度分别为44 55 66 ,则1010 号蚯蚓的向后33 数字串 4562222 号蚯蚓没有向后33 数字串,但其向后22 数字串56,其向后11 数字串5

f(t)f(t) 表示所有蚯蚓中,向后kk 数字串恰好为tt 的蚯蚓只数。

输入输出格式

输入格式:

 

输入文件的第一行有两个正整数n,mn,m ,分别表示蚯蚓的只数与操作次数。

第二行包含nn 个不超过66 的正整数,依次表示编号为1, 2, \dots , n1,2,,n 的蚯蚓的长度。

接下来mm 行,每行表示一个操作。每个操作的格式可以为:

  • 1 i j (1 \leqslant i, j \leqslant n)(1i,jn) 表示:令ii 号与jj 号蚯蚓所在的两个队伍合并为一个队伍,新队伍中,jj 号蚯蚓紧挨在ii 号蚯蚓之后。保证在此操作之前,ii 号蚯蚓在某个队伍的队尾,jj 号蚯蚓在某个队伍的队首,且两只蚯蚓不在同一个队伍中。

  • 2 i (1 \leqslant i \leqslant n)(1in) 表示:令ii 号蚯蚓与紧挨其后一个蚯蚓分离为两个队伍。保证在此操作之前,ii 号蚯蚓不是某个队伍的队尾。

  • 3 s k kk 为正整数,ss 为一个长度至少为kk 的数字串)表示:询问ss 的每个长度为kk 的子串tt f(t)f(t) 的乘积,对998244353998244353 取模的结果。f(t)f(t) 的定义见题目描述。

同一行输入的相邻两个元素之间,用恰好一个空格隔开。

输入文件可能较大,请不要使用过于缓慢的读入方式。

 

输出格式:

 

依次对于每个形如3 s k的操作,输出一行,仅包含一个整数,表示询问的结果。

题目大意:

    一个初始全为单个元素的集合,支持合并,分裂,查询s,k求出s所有长度为k的子串在现有的序列中出现的次数的乘积。

题解:

     ①用链表记录nxt[],pre[]来模拟分裂,合并;

     ②考虑到k<=50,意思就是我们只需要维护长度在50以内串,外加查询其出现的次数。而分裂操作c并不多,意味着合并也并不多。暴力维护即可:每次合并分裂时枚举跨过断点前后50位以内的串修改。

     ③用hash散列表来修改和查询,由于hash的模值比较大,无法开下所有v值,就可以将v类似于存边存进v%sz里,每次修改和查询暴力枚举一遍,复杂度几乎为O(1)

 

 1 #pragma GCC optimize(2)
 2 #include<cstdio>
 3 #include<iostream>
 4 #include<cstring>
 5 #define N 200010
 6 #define M 11000000
 7 #define base 1000000007
 8 #define mod 998244353
 9 #define ull unsigned long long
10 using namespace std;
11 int n,m,pre[N],nxt[N];
12 char tmp[M],*P = tmp,*s,a[N];
13 ull H[M],pw[M];
14 char gc(){
15     static char *p1,*p2,s[1000000];
16     if(p1==p2) p2=(p1=s)+fread(s,1,1000000,stdin);
17     return(p1==p2)?EOF:*p1++;
18 }
19 int rd(){
20     int x = 0,f = 1; char c = gc();
21     while(c<'0'||c>'9') {if(c=='-') f = -1; c = gc();}
22     while(c>='0'&&c<='9') {x = x * 10 + c - '0'; c = gc();}
23     return x * f; 
24 }
25 int rd(char *c){
26     char *st = c;
27     do *c = gc(); while(*c<'0'||*c>'9');
28     do *++c = gc(); while(*c>='0'&&*c<='9');
29     *c = 0;
30     return c - st;
31 }
32 struct Edge{ull v; int nt,w;};
33 const int sz = 1e7;
34 struct HASH{
35     Edge E[sz + 1]; int o,hd[sz + 1]; 
36     int& adde(ull v){
37         E[++o] = (Edge){v,hd[v%sz],0}; hd[v%sz] = o;
38         return E[o].w;
39     }
40     int& operator [] (ull v){
41         for(int i = hd[v%sz];i;i=E[i].nt)
42         if(E[i].v==v) return E[i].w;
43         return adde(v);
44     }
45     int val(ull v){
46         for(int i = hd[v%sz];i;i=E[i].nt)
47         if(E[i].v==v) return E[i].w;
48         return 0;
49     }
50 }Hash;
51 void cal(int y,int x){
52     static char S[N]; int len = 0,fg;
53     int st;for(st = y;pre[st]&&len<=50;st = pre[st],len++); fg = ++len;
54     int ed;for(ed = y;nxt[ed]&&len<=100;ed = nxt[ed],len++);
55     len = 0; //S[++len] = a[st];
56     for(int i = st;nxt[i];i = nxt[i]) S[++len] = a[i]; 
57     S[++len] = a[ed];
58     for(int i = 1;i <= len;i++) H[i] = H[i - 1]*base +  S[i];
59     for(int i = fg;i <= len;i++)
60     for(int j = max(i - 50,0);j < fg - 1;j++){
61         Hash[H[i] - H[j] * pw[i - j]]+=x;
62     }
63 }
64 int main()    
65 {    //freopen("mzoj1112.in","r",stdin);
66     //freopen("mzoj1112.out","w",stdout);
67     n = rd(); m = rd();
68     for(int i = pw[0] = 1;i < M;i++) pw[i] = pw[i - 1] * base;
69     for(int i = 1;i <= n;i++) Hash[a[i] = rd() + '0']++;
70     for(int i = 1,typ,x,y,len,k;i <= m;i++){
71         typ = rd();
72         if(typ==1) {
73             x = rd(); y = rd();
74             pre[y] = x; nxt[x] = y;
75             cal(y,1);
76         }
77         else if(typ==2){
78             x = rd(); y = nxt[x];
79             cal(y,-1);
80             pre[y] = nxt[x] = 0;
81         }
82         else{
83             s = P; len = rd(s+1); P += len + 2; k = rd();
84             ull ans = 1;
85             for(int i = 1;i <= len;i++){
86                 H[i] = H[i - 1]*base + s[i];
87                 if(i>=k) {
88                     ull temp = H[i] - H[i - k] * pw[k];
89                     ans = ans * Hash.val(temp) % mod;
90                 }
91             }
92             printf("%llu\n",ans); 
93         }
94     } 
95     return 0;
96 }//by tkys_Austin;

 

 

 

     

posted @ 2018-03-16 11:27  大米饼  阅读(203)  评论(0编辑  收藏  举报