列表

详情


NC17903. [NOI2017]蚯蚓排队

描述

蚯蚓幼儿园有n 只蚯蚓。幼儿园园长神刀手为了管理方便,时常让这些蚯蚓们列队表演。
所有蚯蚓用从1 到n 的连续正整数编号。每只蚯蚓的长度可以用一个正整数表示,根据入园要求,所有蚯蚓的长度都不超过6 。神刀手希望这些蚯蚓排成若干个队伍,初始时,每只蚯蚓各自排成一个仅有一只蚯蚓的队伍,该蚯蚓既在队首,也在队尾。
神刀手将会依次进行m 次操作,每个操作都是以下三种操作中的一种:
1. 给出i 和j ,令i 号蚯蚓与j 号蚯蚓所在的两个队伍合并为一个队伍,具体来说,令j 号蚯蚓紧挨在i 号蚯蚓之后,其余蚯蚓保持队伍的前后关系不变。
2. 给出i ,令i 号蚯蚓与紧挨其后的一只蚯蚓分离为两个队伍,具体来说,在分离之后,i 号蚯蚓在其中一个队伍的队尾,原本紧挨其后的那一只蚯蚓在另一个队伍的队首,其余蚯蚓保持队伍的前后关系不变。
3. 给出一个正整数k 和一个长度至少为k 的数字串s ,对于s 的每个长度为k 的连续子串t ,定义函数f (t),询问所有这些 f (t) 的乘. 积. 对 998244353 取模后的结果。其中 f (t) 的定义如下:
对于当前的蚯蚓队伍,定义某个蚯蚓的向. 后. k 数. 字. 串. 为:从该蚯蚓出发,沿队伍的向后方向,寻找最近的k 只蚯蚓(包括其自身),将这些蚯蚓的长度视作字符连接而成的数字串;如果这样找到的蚯蚓不足 k 只,则其没有向. 后. k 数. 字. 串. 。例如蚯蚓的队伍为10 号蚯蚓在队首,其后是22 号蚯蚓,其后是3 号蚯蚓(为队尾),这些蚯蚓的长度分别为 4 、5 、6 ,则 10 号蚯蚓的向. 后. 3 数. 字. 串. 为 456,22 号蚯蚓没有向. 后. 3 数.字. 串. ,但其向. 后. 2 数. 字. 串. 为 56,其向. 后. 1 数. 字. 串. 为 5。而 f (t) 表示所有蚯蚓中,向. 后. k 数. 字. 串. 恰好为 t 的蚯蚓只数。

输入描述

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

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

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

1 i j(1≤i,j≤n)表示:令 i 号与 j 号蚯蚓所在的两个队伍合并为一个队伍,新队伍中, j 号蚯蚓紧挨在 i 号蚯蚓之后。保证在此操作之前, i 号蚯蚓在某个队伍的队尾, j 号蚯蚓在某个队伍的队首,且两只蚯蚓不在同一个队伍中。
2 i(1≤i≤n)表示:令 i 号蚯蚓与紧挨其后一个蚯蚓分离为两个队伍。保证在此操作之前, i 号蚯蚓不是某个队伍的队尾。
3 s k(k 为正整数,s 为一个长度至少为 k 的数字串)表示:询问 s 的每个长度为 k的子串 t 的 f(t) 的乘积,对 998244353 取模的结果。 f(t) 的定义见题目描述。

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


输出描述

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

示例1

输入:

5 9
3 1 3 5 3
3 333135 2
3 333135 1
1 1 3
1 2 5
1 3 2
1 5 4
3 333135 2
3 333135 1
3 333135 3

输出:

0
81
1
81
0

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++11(clang++ 3.9) 解法, 执行用时: 1938ms, 内存消耗: 133736K, 提交时间: 2020-05-20 13:45:06

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ull unsigned long long
#define ll long long
#define RG register
#define MAX 222222
#define MOD 998244353
const int base=233;
inline int read(){
    RG int x=0,t=1;RG char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=-1,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return x*t;
}
char ch[10000010];
ull pw[MAX],has[MAX];
int nt[MAX],lt[MAX],a[MAX],g[MAX<<1];
int n,m;
const int mod=7654321;
struct Hash_Table{
    int h[mod],cnt;struct Line{int len,next,w;ull s;}e[10000000];
    void Add(int len,ull s,int w){
        int u=s%mod;
        for(int i=h[u];i;i=e[i].next)
            if(e[i].len==len&&e[i].s==s)
            {e[i].w=(e[i].w+w)%MOD;return;}
        e[++cnt]=(Line){len,h[u],w,s};h[u]=cnt;
    }
    int Query(int len,ull s){
        int u=s%mod;
        for(int i=h[u];i;i=e[i].next)
            if(e[i].len==len&&e[i].s==s)
                return e[i].w;
        return 0;
    }
}Hash;
void Link(int x,int y){
    nt[x]=y;lt[y]=x;
    ull ls=0;int tot=0;
    for(int i=x,len=49;i&&len;i=lt[i],--len){
        ull s=0;ls+=a[i]*pw[tot++];s=ls;int l=tot+1;
        for(int j=y;j&&l<=50;j=nt[j],++l)s=s*base+a[j],Hash.Add(l,s,1);
    }
}
void Cut(int x){
    int y=nt[x];ull ls=0;int tot=0;
    for(int i=x,len=49;i&&len;i=lt[i],--len){
        ull s=0;ls+=a[i]*pw[tot++];s=ls;int l=tot+1;
        for(int j=y;j&&l<=50;j=nt[j],++l)s=s*base+a[j],Hash.Add(l,s,MOD-1);
    }
    nt[x]=lt[y]=0;
}
int Query(int len){
    int l=strlen(ch+1),ret=1;ull s=0;
    for(int i=1;i<len;++i)s=s*base+ch[i]-48;
    ch[0]='0';
    for(int i=len;i<=l;++i){
        s=s*base+ch[i]-48;
        s-=pw[len]*(ch[i-len]-48);
        ret=1ll*ret*Hash.Query(len,s)%MOD;
    }
    return ret;
}
int main(){
    pw[0]=1;for(int i=1;i<MAX;++i)pw[i]=pw[i-1]*base;
    n=read();m=read();
    for(int i=1;i<=n;++i)Hash.Add(1,a[i]=read(),1);
    while(m--){
        int opt=read();
        if(opt==1){
            int x=read(),y=read();
            Link(x,y);
        }
        else if(opt==2){Cut(read());}
        else{
            scanf("%s",ch+1);int k=read();
            printf("%d\n",Query(k));
        }
    }
    return 0;
}

上一题