牛客五一集训排队day3(A、J)

A:

题目描述:


Today, Rikka is going to learn how to use BIT to solve some simple data structure tasks. While studying, She finds there is a magic expression x&(−x)x \& (-x)x&(−x) in the template of BIT. After searching for some literature, Rikka realizes it is the implementation of the function lowbit(x)\text{lowbit(x)}lowbit(x).

lowbit(x)\text{lowbit}(x)lowbit(x) is defined on all positive integers. Let a1...am be the binary representation of x while a1 is the least significant digit, k be the smallest index which satisfies ak = 1. The value of lowbit(x)\text{lowbit}(x)lowbit(x) is equal to 2k-1.

After getting some interesting properties of lowbit(x)\text{lowbit}(x)lowbit(x), Rikka sets a simple data structure task for you:

At first, Rikka defines an operator f(x), it takes a non-negative integer x. If x is equal to 0, it will return 0. Otherwise it will return x−lowbit(x)x-\text{lowbit}(x)x−lowbit(x) or x+lowbit(x)x+\text{lowbit}(x)x+lowbit(x), each with the probability of 12\frac{1}{2}21​.

Then, Rikka shows a positive integer array A of length n, and she makes m operations on it.

There are two types of operations:
1. 1 L R, for each index i ∈ [L,R], change Ai to f(Ai).
2. 2 L R, query for the expectation value of ∑i=LRAi\sum_{i=L}^R A_i∑i=LR​Ai​. (You may assume that each time Rikka calls f, the random variable used by f is independent with others.)

输入描述:


The first line contains a single integer t(1 ≤ t ≤ 3), the number of the testcases.

The first line of each testcase contains two integers n,m(1 ≤ n,m ≤ 105). The second line contains n integers Ai(1 ≤ Ai ≤ 108).

And then m lines follow, each line contains three integers t,L,R(t ∈ {1,2}, 1 ≤ L ≤ R ≤ n).

输出描述:


For each query, let w be the expectation value of the interval sum, you need to output (w×2nm)mod  998244353(w \times 2^{nm}) \mod 998244353(w×2nm)mod998244353.

It is easy to find that w x 2nm must be an integer.

示例:

输入:

1
3 6
1 2 3
1 3 3
2 1 3
1 3 3
2 1 3
1 1 3
2 1 3

输出:

1572864
1572864
1572864
 

题意:

给出一个大小为n的数组,对它进行以下两种操作:

操作1:给出l,r两个值,将[l,r]区间内每一个值x等概率得替换成x-bit(x)和x+bit(x).

操作2:给出L,R两值,求出该区间的期望值

题解:

对于操作一,我们很容易发现x替换后的f(x)的数学期望=0.5(x-bit(x))+0.5(x+bit(x))=x

则进行操作一时,可以在期望的角度对其不进行操作

对于操作二,求出区间和再乘以2的mn次方便可以求出答案

代码:

#include <bits/stdc++.h>
using namespace std;
//typedef long long ll; //  -9223372036854775807ll - 1 ~ 9223372036854775807ll  
#define int long long
#define INF 0X7FFFFFFF
#define MAXN 1000005
#define nullptr 0
#define debug(x) cout<<#x<<" : "<<x<<endl
#define Enter(i,n) (i==n) ? cout<<endl : cout<<" "
#define loop(i,x,n) for( int i = x ; i <= n ; ++i )
#define loop_(i,x,n) for( int i = x ; i >= n ; --i )
#define input(x) scanf("%lld",&x)
#define output(x) printf("%lld",x)
#define new_line printf("\n")
#define blank printf(" ")
const int MAX=0x3f3f3f3f3f3f3f3f;
const int mod=1e9+7;
const int Max=998244353;
const double eps=1e-8;
//代码预处理区域---------------------------------------------------------------------------------


int min(int x,int y){ return ( x & ( ( x-y ) >> 63 ) ) | ( y & ( ~ ( x-y ) >> 63 ) ) ; } 
int max(int x,int y){ return ( y & ( ( x-y ) >> 63 ) ) | ( x & ( ~ ( x-y ) >> 63 ) ) ; } 

int QuickPow( int x , int pow )
{
    int res = 1 ;
    x %= Max ;
    // x %= mod ;
    while( pow ){
        if( pow & 1 ) res = ( res * x ) % Max  ;
        // if( pow & 1 ) res = ( res * x ) % mod  ;
        // if( pow & 1 ) res = res * x ;
        x = ( x * x ) % Max ;
        // x = ( x * x ) % mod ;
        // x = x*x ;
        pow >>= 1 ;
    }
    return res % Max ;
    // return res ;
    // return res % mod ;
}

int gcd( int a , int b )
{
    if(!b) return a ;
    return gcd( b , a%b ) ;
}
// 解决方案代码区--------------------------------------------------
const int N = 1e5+7 ;
const int M = 2e6+7 ;

int lowbit( int x )
{
    return x & (-x) ;
}
int a[N] ;
int sum[N] ;
void solve() 
{
    int n , m ;
    cin >> n >> m ;
    int x ;
    for( int i = 1 ; i <= n ; i ++ ){
        cin >> x ;
        a[i] = x ;
        sum[i] = sum[i-1]+a[i] ;
    }
    int p , l , r ;
    for( int i = 1 ; i <= m ; i ++ ){
        cin >> p >> l >> r ;
        if( p == 2 ){
           int ans = sum[r] - sum[l-1] ;
           cout << ans%Max*QuickPow( 2 , n*m )%Max << endl ;
        }
    }
    return ;
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr),cout.tie(nullptr);
    int _ = 1 ;
    // input( _ ) ;
    cin >> _ ;
    // init() ;
    while( _-- ){
//        srand( (int)time(0) ) ;
        solve() ;
    }
    return 0;
}

B:

题目描述:


Sometimes you may want to write a sentence into your nickname like "lubenwei niubi". But how to change it into a single word? Connect them one by one like "lubenweiniubi" looks stupid.

To generate a better nickname, Rikka designs a non-trivial algorithm to merge a string sequence s1...sn into a single string. The algorithm starts with s=s1 and merges s2...sn into s one by one. The result of merging t into s is the shortest string r which satisfies s is a prefix of r and t is a subsequence of r.(If there are still multiple candidates, take the lexicographic order smallest one.)

String s is a prefix of r if and only if |s| ≤ |r| and for all index i ∈ [1, |s|], si = ri.

String s is a subsequence of r if and only if there is an index sequence a1...a∣s∣(1≤a1<a2<...<a∣s∣≤∣r∣)a_1...a_{|s|}( 1 \leq a_1 < a_2 < ... < a_{|s|} \leq |r|)a1​...a∣s∣​(1≤a1​<a2​<...<a∣s∣​≤∣r∣) which satisfies si=rais_i = r_{a_i}si​=rai​​.

For example, if we want to generate a nickname from "lubenwei niubi", we will merge "niubi" into "lubenwei", and the result is "lubenweiubi".

Now, given a sentence s1...sn with n words, Rikka wants you to calculate the resulting nickname generated by this algorithm.

输入描述:


The first line contains a single number t(1 ≤ t ≤ 3), the number of testcases.

For each testcase, the first line contains one single integer n(1 ≤ n ≤ 106).

Then n lines follow, each line contains a lowercase string si(1≤∣si∣≤106,∑i=1n∣si∣≤106)s_i(1 \leq |s_i| \leq 10^6, \sum_{i=1}^n |s_i| \leq 10^6)si​(1≤∣si​∣≤106,∑i=1n​∣si​∣≤106).

输出描述:


For each testcase, output a single line with a single string, the result nickname.

示例:

输入:

2
2
lubenwei
niubi
3
aa
ab
abb

输出:

lubenweiubi
aabb

题意:

对于每一组数据,首先给出一个数字n来描述所需合并的字符串。首先输入的字符串会不变得作为绰号的开头(且称作主串),接下来每一行的字符串会从主串的第一个字母开始扫描,如果有相同的字母则该字母不接着录入字串,主串指针不回溯。最后输出这个主串

题解:

首先记录主串(第一个字符串)的每一个字符数目以及位置,在接下来的字串中,对于每一个子串:记录每一个字符的个数a[x]并初始化为0,主串上的指针重置为0,对于子串上的每一个字符,主串指针不断递增去去找是否有元素与之对应,如果有那么a[x]++,出现未有的情况则直接把后续字符全部录入,同时完善主串的字符记录。

通过代码:

//floor();向下取整
//ceil();向上取整
//rand();随机数
#include <bits/stdc++.h>
using namespace std;
//typedef long long ll; //  -9223372036854775807ll - 1 ~ 9223372036854775807ll  
#define int long long
#define INF 0X7FFFFFFF
#define MAXN 1000005
#define nullptr 0
#define debug(x) cout<<#x<<" : "<<x<<endl
#define Enter(i,n) (i==n) ? cout<<endl : cout<<" "
#define loop(i,x,n) for( int i = x ; i <= n ; ++i )
#define loop_(i,x,n) for( int i = x ; i >= n ; --i )
#define input(x) scanf("%lld",&x)
#define output(x) printf("%lld",x)
#define new_line printf("\n")
#define blank printf(" ")
const int MAX=0x3f3f3f3f3f3f3f3f;
const int mod=1e9+7;
const int Max=998244353;
const double eps=1e-8;
//代码预处理区域---------------------------------------------------------------------------------


int min(int x,int y){ return ( x & ( ( x-y ) >> 63 ) ) | ( y & ( ~ ( x-y ) >> 63 ) ) ; } 
int max(int x,int y){ return ( y & ( ( x-y ) >> 63 ) ) | ( x & ( ~ ( x-y ) >> 63 ) ) ; } 

int QuickPow( int x , int pow )
{
    int res = 1 ;
    // x %= Max ;
    x %= mod ;
    while( pow ){
        // if( pow & 1 ) res = ( res * x ) % Max  ;
        if( pow & 1 ) res = ( res * x ) % mod  ;
        // if( pow & 1 ) res = res * x ;
        // x = ( x * x ) % Max ;
        x = ( x * x ) % mod ;
        // x = x*x ;
        pow >>= 1 ;
    }
    // return res % Max ;
    // return res ;
    return res % mod ;
}

int gcd( int a , int b )
{
    if(!b) return a ;
    return gcd( b , a%b ) ;
}
// 解决方案代码区--------------------------------------------------
const int N = 1e5+7 ;
const int M = 2e6+7 ;

vector< int > pos[30] ; 
int a[30] ;
void solve() 
{
    for( int i = 0 ; i < 26 ; i ++ ) pos[i].clear() ;
    int n ;
    cin >> n ;
    string s ;
    cin >> s ;
    for( int i = 0 ; i < s.size() ; i ++ ){
        pos[ s[i]-'a' ].push_back( i ) ;
    }
    string p ;
    for( int i = 2 ; i <= n ; i ++ ){
        memset( a , 0 , sizeof a ) ;
        cin >> p ;
        int t = -1 ;
        for( int j = 0 ; j < p.size() ; j ++ ){
            int x = p[j]-'a' ;
            if( pos[x].size() > a[x] ){
                if( pos[x][ a[x] ] > t ){
                    t = pos[x][ a[x] ] ;
                    a[x]++ ;
                }
                else {
                    int temp = a[x] ;
                    while( pos[x][ temp ] < t && temp < pos[x].size() ){
                        temp ++ ;
                    }
                    if( temp < pos[x].size() ){
                        t = pos[ x ][temp] ;
                        a[x] = temp+1 ;
                    }
                    else {
                        int len = s.size() ;
                        for( int k = j ; k < p.size() ; k ++ ){
                            pos[ p[k]-'a' ].push_back( len++ ) ;
                            s += p[k] ;
                        }
                        break ;
                    }
                }
            }
            else{
                int len = s.size() ;
                for( int k = j ; k < p.size() ; k ++ ){
                    pos[ p[k]-'a' ].push_back( len++ ) ;
                    s += p[k] ;
                }
                break ;
            }
        }
        
    }
    cout << s << endl ;
    return ;
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr),cout.tie(nullptr);
    int _ = 1 ;
    // input( _ ) ;
    cin >> _ ;
    // init() ;
    while( _-- ){
//        srand( (int)time(0) ) ;
        solve() ;
    }
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值