洛谷3823 [NOI2017] 蚯蚓排队 【哈希】

题目分析:

从$\sum|S|$入手。共考虑$\sum|S|$个$f(t)$。所以我们要一个对于每个$f(t)$在$O(1)$求解的算法。不难想到是哈希。

然后考虑分裂和合并操作。一次合并操作要考虑合并点之前的$O(k)$个点向后衔接的哈希值。共$O(k^2)$。看似超时实则不然。一个串最多$O(nk)$个哈希结果,所以均摊入手。

对于分裂和重合并不能均摊,所以多了一个$O(ck^2)$。

这题的合并和分裂只和合并点和分裂点有关,而这个信息是给出的,所以不需要额外使用数据结构维护结果。

时间复杂度$O(nk+mk+ck^2+\sum |s|)$

 

代码:

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<cstdlib>
  5 using namespace std;
  6 
  7 const int maxsz = 450;
  8 const int maxn = 505000;
  9 const int mod = 998244353;
 10 const int hmod1 = 19260817;
 11 const int hmod2 = 19491001;
 12 
 13 int n,m,maxx;
 14 int a[maxn],pts[maxn];
 15 int ans[maxn],Num,nouse[94],nuse[91];
 16 int hsh[hmod1+5],Nxt[maxn*25],real[maxn*25],val[maxn*25],hnum;
 17 
 18 struct query{ int cas;string str; int l,r; }Q[maxn];
 19 
 20 int global = 0;
 21 
 22 struct linktable{int pre[maxn>>1],nxt[maxn>>1];}T;
 23 
 24 void in(int &x){
 25     char ch = getchar();
 26     while(ch > '9' || ch < '0') ch = getchar();
 27     while(ch <= '9' && ch >= '0') x = x*10+ch-'0',ch = getchar();
 28 }
 29 
 30 void readstring(string &str){
 31     char ch = getchar();
 32     while(ch > '9' || ch < '0') ch =getchar();
 33     while(ch <= '9' && ch >= '0') str.push_back(ch),ch=getchar();
 34 }
 35 
 36 void read(){
 37     in(n),in(m);
 38     for(int i=1;i<=n;i++) {in(a[i]);}
 39     for(int i=1;i<=m;i++){
 40     in(Q[i].cas);
 41     if(Q[i].cas == 1) in(Q[i].l),in(Q[i].r);
 42     else if(Q[i].cas == 2) in(Q[i].l);
 43     else {readstring(Q[i].str),in(Q[i].l);Q[i].r = ++Num;maxx = max(maxx,Q[i].l);}
 44     }
 45 }
 46 
 47 int imnum[60],numnum;
 48 
 49 void Add_hash(int a1,int a2,int dr){
 50     int p1 = hsh[a1];
 51     while(true) {
 52     if(real[p1] == a2) {val[p1]+=dr;return;}
 53     if(Nxt[p1]) p1 = Nxt[p1];
 54     else break;
 55     }
 56     hnum++; if(p1) Nxt[p1] = hnum;
 57     p1 = hnum; val[p1] = 1; real[p1] = a2;
 58     if(!hsh[a1]) hsh[a1] = p1;
 59 }
 60 
 61 void buildnew(int lft,int rgt,int dr){
 62     numnum = 0;int now = lft;
 63     while(true){
 64     if(numnum == maxx-1) break;
 65     imnum[++numnum] = a[now];
 66     if(T.pre[now]) now = T.pre[now];
 67     else break;
 68     }
 69     now = rgt;long long um = 0,vm = 0;
 70     for(int i=1;i<=numnum;i++){
 71     um = (1ll*nouse[i-1]*imnum[i]+um)%hmod1;
 72     vm = (1ll*nuse[i-1]*imnum[i]+vm)%hmod2;
 73     long long r1 = um,r2 = vm;
 74     for(int j=i+1,jj=rgt;j<=maxx;j++){
 75         r1 = (r1*10+a[jj])%hmod1; r2 = (r2*10+a[jj])%hmod2;
 76         Add_hash(r1,r2,dr); if(!T.nxt[jj])break; jj = T.nxt[jj];
 77         global++;
 78     }
 79     }
 80 }
 81 
 82 void link(int lft,int rgt){
 83     buildnew(lft,rgt,1);
 84     T.nxt[lft] = rgt; T.pre[rgt] = lft;
 85 }
 86 
 87 void cut(int place){
 88     buildnew(place,T.nxt[place],-1);
 89     T.pre[T.nxt[place]] = 0; T.nxt[place] = 0;
 90 }
 91 
 92 int COUNT(int alpha,int beta){
 93     int fw = 0;
 94     for(int i=hsh[alpha];i;i=Nxt[i]){
 95     if(real[i] != beta) continue; 
 96     fw += val[i];
 97     }
 98     return fw; 
 99 }
100 
101 void work(){
102     for(int i=1;i<=n;i++) nouse[a[i]]++;
103     for(int i=1;i<=m;i++){
104     if(Q[i].cas != 3 || Q[i].l != 1) continue;
105     int fw = 1; for(int j=0;j<Q[i].str.length();j++){fw = (1ll*fw*nouse[Q[i].str[j]-'0'])%mod;}
106     ans[Q[i].r] = fw;
107     }
108     memset(nouse,0,sizeof(nouse)); nouse[0] = 1;nuse[0] = 1;
109     for(int i=1;i<=55;i++) nouse[i] = (nouse[i-1]*10ll)%hmod1,nuse[i] = (nuse[i-1]*10ll)%hmod2;
110     
111     for(int i=1;i<=m;i++){
112     if(Q[i].cas == 1) link(Q[i].l,Q[i].r);
113     else if(Q[i].cas == 2) cut(Q[i].l);
114     else{
115         if(Q[i].l == 1) continue; 
116         int fw = 1;long long hres1=0,hres2 = 0;
117         for(int j=0;j<Q[i].l;j++){ 
118         hres1 = hres1*10+Q[i].str[j]-'0'; 
119         hres2 = hres2*10+Q[i].str[j]-'0';
120         hres1 %= hmod1; hres2 %= hmod2;
121         }
122         fw = (1ll*fw*COUNT(hres1,hres2))%mod;
123         for(int j=Q[i].l;j<Q[i].str.length();j++){
124         hres1 -= ((Q[i].str[j-Q[i].l]-'0')*nouse[Q[i].l-1])%hmod1;
125         hres1 += hmod1; hres1 %= hmod1;
126         hres2 -= ((Q[i].str[j-Q[i].l]-'0')*nuse[Q[i].l-1])%hmod2;
127         hres2 += hmod2; hres2 %= hmod2;
128         hres1 = (hres1*10+Q[i].str[j]-'0');hres1 %= hmod1;
129         hres2 = (hres2*10+Q[i].str[j]-'0');hres2 %= hmod2;
130         fw = (1ll*fw*COUNT(hres1,hres2))%mod;
131         }
132         ans[Q[i].r] = fw;
133     }
134     }
135     for(int i=1;i<=Num;i++) printf("%d\n",ans[i]);
136 }
137 
138 int main(){
139     read();
140     work();
141     return 0;
142 }

 

posted @ 2018-06-22 19:41  menhera  阅读(180)  评论(0编辑  收藏  举报