[NOI2017]蚯蚓排队

Description
  给出 n n 个字符,初始每个字符单独成字符串。支持m次操作,每次为一下三种之一:
   1 1 i j j :将以i结尾的串和以 j j 开头的串连到一起。
  2 i i :将i所在串从 i i 位置和i下一个位置之间断开。
   3 3 S k k :对于字符串S每个长度为 k k 的子串,统计它在这n个字符组成所有字符串中出现的次数,求所有统计结果的乘积模 998244353 998244353 的结果。
   n2e5 n ≤ 2 e 5 m3e5 m ≤ 3 e 5 Σ|s|<1e7 Σ | s | < 1 e 7 k50 k ≤ 50
   2 2 操作次数小于1e3
 
Solution

(●´∀`)♪我miao掉了好开心啊,我原来这么厉害啊哈哈哈哈哈

蛤蛤蛤开始码码码码码码码码码码码码码码码码码码码码码码码码

(っ °Д °;)っ啊啊啊为毛球不对啊啊啊啊啊啊啊啊啊啊啊啊啊啊
(っ °Д °;)っ啊啊啊大样例WAWAWAWAWAWAWAWAWAWAWAWAWA
(/゚Д゚)/ 为毛球换个模数错的地方就不一样了啊,只好承认自己菜去抄题解

(/゚Д゚)/ 你什么东西啊,先自然溢然后哈希表,只好%%%%%%%%%

  事实证明没有卡自然溢,大家以后可以放心使用。。
  我开始用了几个 1e6 1 e 6 级别的模数,直接开 MP M ∗ P 的数组记 cnt c n t ,都死的很惨。。。

  那么白菜 miaowey m i a o w e y 又涨了姿势,用自然溢套哈希表!
  (对了让我们背好长者的生日吧这是个质数蛤蛤蛤 19260817 19260817
  
 Source
 

//2018-4-24
//miaowey
//Read()
#include <bits/stdc++.h>
using namespace std;

#define ULL unsigned long long
#define For(i, a, b) for(int i = (a); i <= (int)(b); ++i)

#define M (50 + 2)
#define N (200000 + 2)

char chr;
inline void Read(int &x){
    chr = getchar();
    while(chr < '0' || chr > '9') chr = getchar();
    x = 0;
    while(chr >= '0' && chr <= '9'){
        x = (x << 1) + (x << 3) + (chr ^ '0');
        chr = getchar();
    }
}

const ULL A = 7;
const int P = 19260817, RP = 998244353;

struct node{
    int pre, nxt, len; ULL num[M];
}h[N];

namespace HashTable{
    int hn, head[P], to[10000005], nxt[10000005], tot[10000005];
    ULL val[10000005];

    void Insert(int id, ULL nv, int ad){
        int o  = nv % P;
        for(int i = head[o]; i; i = nxt[i]) if(to[i] == id && val[i] == nv){
            tot[i] += ad; return;
        }

        to[++hn] = id; nxt[hn] = head[o]; head[o] = hn;
        tot[hn] += ad; val[hn] = nv;
    }

    int Query(int id, ULL nv){
        int o = nv % P;
        for(int i = head[o]; i; i = nxt[i]) if(to[i] == id && val[i] == nv) return tot[i];
        return 0;
    }
};

int n, m, s[N];
ULL powa[M];
char rs[10000005];

void Unit(int u, int v){
    h[v].pre = u; h[u].nxt = v;

    int T = 50, cnt = 0, len = h[v].len;
    ULL add[M];
    For(i, 0, len) add[i] = h[v].num[i];

    while(T --){
        For(i, 1, len) add[i] = add[i] + powa[i + cnt] * s[u];

        ++cnt;
        if(len + cnt > 50) --len;   

        For(i, cnt + 1, cnt + len){
            h[u].num[i] = add[i - cnt], ++h[u].len;

            HashTable::Insert(i, h[u].num[i], 1);
        }

        if(!(u = h[u].pre) || !len) break;
    }
}

void Cut(int u){
    int v = h[u].nxt;
    h[u].nxt = h[v].pre = 0;

    int T = 50, len = 0;

    while(T --){
        int flen = h[u].len;
        h[u].len = ++len;

        For(i, len + 1, flen) HashTable::Insert(i, h[u].num[i], -1);

        if(!(u = h[u].pre)) break;
    }
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("queue5.in", "r", stdin);
    freopen("queue.out", "w", stdout);
#endif

    powa[0] = 1;
    For(i, 1, 50) powa[i] = powa[i - 1] * A;

    Read(n), Read(m);
    For(i, 1, n){
        Read(s[i]); h[i].num[1] = s[i];
        h[i].len = 1; HashTable::Insert(1, s[i], 1);
    }

    int op, u, v, k, rlen;

    while(m --){
        Read(op);

        if(op == 1){
            Read(u), Read(v); Unit(u, v);

        }else if(op == 2){
            Read(u); Cut(u);

        }else{
            scanf("%s", rs + 1); Read(k);
            rlen = strlen(rs + 1);

            ULL now = 0; int ans = 1;
            For(i, 1, k - 1) now = now * A + (rs[i] - '0');

            For(i, k, rlen){
                now = now * A + (rs[i] - '0');
                ans = (long long)ans * (HashTable::Query(k, now)) % RP;

                now -= powa[k - 1] * (rs[i - k + 1] - '0');
            }

            printf("%d\n", ans);
        }
    }


    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值