Loading

蚯蚓排队(码)

蚯蚓排队 解题报告

·题面

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

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

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

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

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

  3. 给出一个正整数 \(k\) 和一个长度至少为 \(k\) 的数字串 \(s\) ,对于 \(s\) 的每个长度为 \(k\) 的连续子串 \(t\) (这样的子串共有 \(∣s∣−k+1\) 个,其中 \(∣s∣\)\(s\) 的长度),定义函数 \(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\) 的蚯蚓只数。

·\(Input\)

输入文件的第一行有两个正整数 \(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)\) 的定义见题目描述。

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

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

·Output

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

·样例输入

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

·\(code\)

相信看码的你,可以看懂

#include<bits/stdc++.h> 
#define int unsigned long long 
#define together ios::sync_with_stdio( 0 ) ; cin.tie( 0 ) ; cout.tie( 0 )  
using namespace std ; 
//unordered_map<int,int>hasher;
const int down = 131 ; 
const int Last_mod = 998244353 ; 
const int N = 1e6 + 100 ; 
const int mod = 10000019 ; 
const int CuFeO4 = 2e7 + 20 ;
int does[ 60 ] , n , m  , opt ;  
int length[ N ] ; int Next_point[ N ] , Pre_point[ N ] ; 
int Max_k = 50 ; 
namespace HASH
{
    struct Hash_Table_Of_List
    {  
        struct One_node 
        {
            int key_save ;
            int value , next ;
        } ;
        One_node grass[ CuFeO4 << 1 ] ;   
        int head[ CuFeO4 << 1 ] , cnt ;
        int Hash_return( int key ) 
        { 
            return ( key % mod + mod ) % mod ; 
        }
        int& operator[]( int key_in ) 
        {
            int inlist = Hash_return( key_in ) ;  // 获取头指针
            for (int i = head[ inlist ] ; i; i = grass[ i ].next )
            if ( grass[ i ].key_save == key_in )
            return grass[ i ].value ;
            return grass[ ++ cnt ] = ( One_node ){ key_in, 0, head[ inlist ] } , head[ inlist ] = cnt , grass[ cnt ].value ;
        }
        Hash_Table_Of_List( ) 
        {
            cnt = 0;
            memset( head , 0 , sizeof( head ) ) ; 
        }
}hasher;

    inline void insert( )
    {
        int x , y ; 
        cin >> x >> y ; 
        Next_point[ x ] = y ; 
        Pre_point[ y ] = x ; 
        int omega = 0 ; 
        for( int i = x , len = 1 ; i > 0 && len < 50  ; ++ len , i = Pre_point[ i ] ) 
        {
            int Klen = len + 1 , pomega ; 
            pomega = omega = ( omega  + ( does[ len - 1 ] * ( length[ i ] + '0' ) )  )  ; 
            // cout <<  ( length[ i ] + '0' ) << ' ' ; 
            // cout << omega << '\n' ; 
            for ( int j = y ;  j > 0 && Klen <= 50 ;  ++ Klen , j = Next_point[ j ] ) 
            {
                pomega = ( pomega * down + length[ j ] + '0' )  ; 
                hasher[ pomega ] = ( hasher[ pomega ] + 1 ) % Last_mod ; 
                //  cout << length[ i ] <<' ' << i << ' ' << length[ j ] << ' ' << j << ' '  ; 
                //  cout <<  pomega  << '\n' ; 
            }
        }
    }
    inline void cut_off( )
    {
        int x ; 
        cin >> x ; 
        int y = Next_point[ x ] ; 
        Pre_point[ Next_point[ x ] ] = 0 ; 
        Next_point[ x ] = 0 ; 
        int omega = 0 ; 
        for( int i = x , len = 1 ; i > 0 && len < 50  ; ++ len , i = Pre_point[ i ] ) 
        {
            int Klen = len + 1 , pomega ; 
            pomega = omega = ( omega  + ( does[ len - 1 ] * ( length[ i ] + '0' ) )  )  ; 
            // cout <<  ( length[ i ] + '0' ) << ' ' ; 
            // cout << omega << '\n' ; 
            for ( int j = y ;  j > 0 && Klen <= 50 ; ++ Klen , j = Next_point[ j ] ) 
            {
                pomega = ( pomega * down + length[ j ] + '0' )  ; 
                hasher[ pomega ] = ( hasher[ pomega ] - 1 ) % Last_mod ; 
                // cout << length[ i ] <<' ' << i << ' ' << length[ j ] << ' ' << j << ' '  ; 
                // cout <<  pomega  << '\n' ; 
            }
        }
    }
    inline void query( )
    {
        int k ; char s[ N ] ; 
        cin >> s + 1 >> k ; 
        int ans = 1 ; 
        int lens = strlen( s + 1 ) ;
        int hash_s = 0 ; 
        for( int i = 1 ; i <= k ; ++ i )
        {
           //cout << does[ k - i ] * s[ i ] << '\n' ; 
            hash_s = ( hash_s + does[ k - i ] * s[ i ] )  ; 
           //cout << hash_s << '\n' ; 
        }
        //cout << hash_s << endl ; 
        //cout << hasher[ hash_s ] << '\n' ; 
        ans = ( ans * ( hasher[ hash_s ] ) % Last_mod ) % Last_mod ; 
        //cout << ' ' << ans ; 
        //cout << ' ' << k + 1 << lens << '\n' ; 
        for( int i = k + 1 ; i <= lens ; ++ i )
        {
            int st = i - k ; 
            hash_s = ( hash_s - does[ k - 1 ] * s[ st ] )  ; 
            hash_s = ( ( hash_s * down ) + s[ i ] ) ; 
            //cout << hash_s << '\n' ; 
            ans = ( ans * ( hasher[ hash_s ] ) % Last_mod ) % Last_mod ; 
        }
        cout << ans << '\n' ; 
    }
}
using namespace HASH ; 
signed main( )
{
    #ifndef ONLINE_JUDGE
        freopen( "cjs.in" , "r" , stdin ) ;
        freopen( "cjs.out" , "w" , stdout ) ;
    #endif
    together ; 
    does[ 0 ] = 1 ; 
    for( int i = 1 ; i <= 50 ; i ++ )
    {
        does[ i ] = ( does[ i - 1 ] * down ) ; 
    }
    cin >> n >> m ;
    for( int i = 1 ; i <= n ; ++ i )
    {
        cin >> length[ i ] ; 
        hasher[ length[ i ] + '0' ] = hasher[ length[ i ] + '0' ] + 1 ; 
        //cout << length[ i ] << ' ' << hasher[ length[ i ] + '0' ] << '\n' ; 
    }
    //cout << hasher[ '1' ] << ' ' << '\n' ; 
    for( int i = 1 ; i <= m ; ++ i )
    {
        cin >> opt ; 
        switch( opt )
        {
            case 1 : 
            {
                insert( ) ; 
                break ; 
            }
            case 2 : 
            {
                cut_off( ) ; 
                break ; 
            }
            default : 
            {
                query( ) ; 
                break ; 
            }
        }
    }
}

posted @ 2024-02-05 19:56  HANGRY_Sol&Cekas  阅读(21)  评论(0编辑  收藏  举报