ZOJ 2671 -Cryptography ( 矩阵乘法 + 线段树 )

ZOJ 2671 - Cryptography ( 矩阵乘法 + 线段树 )

题意:

给定模数r, 个数n, 询问数m

然后是n个矩阵,每次询问,输出矩阵联乘之后的结果。

分析:

矩阵乘法 + 线段树优化

这里线段树只有询问没有更新操作。

PS:顺便仰慕一下watashi。。。。

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define lson l, m, o << 1
#define rson m + 1, r , o << 1 | 1
#define ls o << 1
#define rs o << 1 | 1
#define rt l, r , o
#define CLR( a, b ) memset( a, b, sizeof(a) )
#define MID ( l + r ) >> 1
#define MAXN 30003

int r, m, n, ll, rr;

struct Mat
{
    int mat[2][2];
    void set( Mat M )
    {
        for( int i = 0; i < 2; ++i )
            for( int j = 0; j < 2; ++j )
                mat[i][j] = M.mat[i][j];
    }
    void init()
    {
        for( int i = 0; i < 2; ++i )
            for( int j = 0; j < 2; ++j )
                mat[i][j] = ( i == j );
    }

}Tree[ MAXN << 2 ], M;

Mat mul( Mat a, Mat b )
{
    Mat c;
    CLR( c.mat, 0 );
    for( int i = 0; i < 2; ++i )
        for( int j = 0; j < 2; ++j )
            for( int k = 0; k < 2; ++k )
                c.mat[i][j] = ( c.mat[i][j] + a.mat[i][k] * b.mat[k][j] ) % r;
    return c;
}

inline void push_up( int o )
{
    Tree[ o ] = mul( Tree[ls], Tree[rs] );
}

void build( int l, int r, int o )
{
    Tree[o].init();
    if( l == r )
    {
        for( int i = 0; i < 2; ++i )
            for( int j = 0; j < 2; ++j )
                scanf( "%d", &M.mat[i][j] );
        Tree[o].set( M );
        return;
    }
    int m = MID;
    build( lson );
    build( rson );
    push_up( o );
}

Mat query( int L, int R, int l, int r, int o )
{
    if( L <= l && r <= R )
        return Tree[o];
    int m = MID;
    if( R <= m )    return query( L, R, lson );
    else if( L > m )    return query( L, R, rson );
    else
    {
        return mul( query( L, m, lson ), query( m + 1, R, rson ) );
    }
}

void Orz()
{
    int cas = 0;
    while( ~scanf( "%d %d %d", &r, &n, &m ) )
    {
        if( cas != 0 )
            putchar( ‘\n‘ );
        cas++;
        build( 1, n, 1 );
        bool blank = false;
        while( m-- )
        {
            if( blank )    putchar( ‘\n‘ );
            else    blank = true;
            scanf( "%d %d", &ll, &rr );
            Mat res = query( ll, rr, 1, n, 1 );
            for( int i = 0; i < 2; ++i )
                printf( "%d %d\n", res.mat[i][0], res.mat[i][1]);
        }
    }
}

int main()
{
    Orz();
    return 0;
}

代码君

时间: 2024-08-27 02:30:44

ZOJ 2671 -Cryptography ( 矩阵乘法 + 线段树 )的相关文章

ZOJ 2671 Cryptography 矩阵乘法+线段树

B - Cryptography Time Limit:5000MS     Memory Limit:32768KB     64bit IO Format:%lld & %llu Submit Status Practice ZOJ 2671 Description Young cryptoanalyst Georgie is planning to break the new cipher invented by his friend Andie. To do this, he must

HDU 5068 Harry And Math Teacher( 矩阵乘法 + 线段树维护 )

HDU 5068 Harry And Math Teacher( 矩阵乘法 + 线段树维护 ) 题意: 首先是这题题意理解错误,,其次是这题无法理解状态... 已经不是英文有多烂的情况了,是中文没学好啊.....大学不学语文才是真正的硬伤啊 题目意思 有一个城堡有很多层楼, 每层楼有2个门,每个门里面又有两个楼梯,可以通往上一层的两个门 问,从x层楼到y层楼有多少中方法(不能返回) 具体看图吧,,,已经不会说话了 1 #include <cstdio> 2 #include <cstri

【XSY2538】/【HDU6155】Subsequence Count(矩阵乘法+线段树)

题目翻译 Description 给定一个\(01\)串 \(S_{1...n}\) 和 \(Q\) 个操作. 操作有两种类型: 1.将 \([l,r]\) 区间的数取反(将其中的\(0\)变成\(1\),\(1\)变成\(0\)). 2.询问字符串 \(S\) 的子串 \(S_{l...r}\) 有多少个不同的子序列.由于答案可能很大,请将答案对 \(10^9+7\) 取模. 在数学中,某个序列的子序列是从最初序列通过去除某些元素但不破坏余下元素的相对位置(在前或在后)而形成的新序列. Inp

ZOJ 3772 Calculate the Function 线段树+矩阵

Calculate the FunctionTime Limit:2000MS     Memory Limit:65536KB     64bit IO Format:%lld & %llu Submit Status Appoint description:  System Crawler  (2014-04-09) Description You are given a list of numbers A1A2 .. AN and M queries. For the i-th query

ZOJ 3633 Alice&#39;s present(线段树)

As a doll master, Alice owns a wide range of dolls, and each of them has a number tip on it's back, the tip can be treated as a positive integer. (the number can be repeated). One day, Alice hears that her best friend Marisa's birthday is coming , so

HDU 6155 Subsequence Count(矩阵 + DP + 线段树)题解

题意:01串,操作1:把l r区间的0变1,1变0:操作2:求出l r区间的子序列种数 思路:设DP[i][j]为到i为止以j结尾的种数,假设j为0,那么dp[i][0] = dp[i - 1][1] + dp[i -1][0] (0结尾新串) + dp[i - 1][0] (0结尾旧串) - dp[i - 1][0] (重复) + 1(0本身被重复时去除). 那么可以得到转移时的矩阵 $$ \left( \begin{matrix} dp[i - 1][0] & dp[i - 1][1] &am

加法乘法线段树模板

P2023 [AHOI2009]维护序列 指定一个区间 加上或者乘以 V, 查询一个区间所有元素和%P 与纯加法线段树不同的是,lazy_tag 的传递 (x + y) * v = xv + yv. 所以每次乘法,都要把加法的lazy_tag * v 而加法与加法线段树的操作一样 #include <iostream> #include <algorithm> typedef long long LL; using namespace std; const int MAXN = 1

zoj 3888 Twelves Monkeys 二分+线段树维护次小值

链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3888 Twelves Monkeys Time Limit: 5 Seconds      Memory Limit: 32768 KB James Cole is a convicted criminal living beneath a post-apocalyptic Philadelphia. Many years ago, the Earth's surf

ZOJ 3911 Prime Query(线段树)

Prime Query Time Limit: 1 Second      Memory Limit: 196608 KB You are given a simple task. Given a sequence A[i] with N numbers. You have to perform Q operations on the given sequence. Here are the operations: A v l, add the value v to element with i