【矩阵快速幂整理】【套路】矩阵快速幂+线段树

pro1
ACM-ICPC 2017 Asia Urumqi: H. Count Numbers
2017乌鲁木齐区域赛 矩阵快速幂+dp

参考博客

小技巧摘录
当矩阵的幂 会爆long long时,不想用java的话,可以这样转化
矩阵的幂可以转换为 M ^(a^b-9)
a^b - 9 = a^(b/2)*a^(b-b/2)-9
我们来看这个问题 a*b-9,可以转换成b*(a-1)+ b-9 ,目的是去掉负号
然后就可以转换成( M^b )^(a-1) * M^(b-9);
这样就要求3次快速幂,其中M^(b-9) 和 M^b 可以继续合并以加快速度。
code在最后。


pro2
HDU 6155 dp+矩阵+线段树
参考博客
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6155
给出一个长度为n的01序列以及Q个操作,操作分两类,一种是将[L,R]内的01序列翻转,二是求出[L,R]中包含多少不同的子序列。

这个题目一是要想到dp方程,二是要想到利用矩阵去表示0和1,同时还要巧妙的表示出首项,第三点是翻转,只要第二点能够想到,那么第三点就不难推出来。


pro3
矩阵快速幂: 网易2017实习生编程题 魔力手环
描述:
小易拥有一个拥有魔力的手环上面有n个数字(构成一个环),当这个魔力手环每次使用魔力的时候就会发生一种奇特的变化:每个数字会变成自己跟后面一个数字的和(最后一个数字的后面一个数字是第一个),一旦某个位置的数字大于等于100就马上对100取模(比如某个位置变为103,就会自动变为3).现在给出这个魔力手环的构成,请你计算出使用k次魔力之后魔力手环的状态。
输入描述:
输入数据包括两行:
第一行为两个整数n(2 ≤ n ≤ 50)和k(1 ≤ k ≤ 2000000000),以空格分隔
第二行为魔力手环初始的n个数,以空格分隔。范围都在0至99.
输出描述:
输出魔力手环使用k次之后的状态,以空格分隔,行末无空格。
输入例子:
3 2
1 2 3
输出例子:
8 9 7

每一次变化,可以看成乘以一个矩阵
1 1 0 0 0 …0
0 1 1 0 0 …0
0 0 1 1 0 …0
.
.
.
1 0 0 0 0… 1
最终结果是乘以这个矩阵k次。使用矩阵快速幂求解。

参考博客


To-do list

https://blog.csdn.net/catherinetang0919/article/details/23207571
https://blog.csdn.net/Mys_C_K/article/details/80429262


pro1code:

这里写图片描述

java版code:


import java.util.*;
import java.math.*;
public class Main {
    static long MOD;
    static class lenka
    {
        long a[][]=new long[20][20];
        lenka()
        {
            for(int i=0;i<18;i++)
            {
                for(int j=0;j<18;j++)a[i][j]=0;
            }
        }
    }
    static lenka cla(lenka a,lenka b)
    {
        lenka c=new lenka();
        for(int i=0;i<18;i++)
        {
            for(int j=0;j<18;j++)
            {
                for(int k=0;k<18;k++)
                {
                    c.a[i][j]+=a.a[i][k]*b.a[k][j]%MOD;
                    c.a[i][j]%=MOD;
                }
            }
        }
        return c;
    }
    static long POW(BigInteger n)
    {
        lenka a=new lenka();
        lenka res=new lenka();
        for(int i=0;i<18;i++)res.a[i][i]=1;
        for(int i=0;i<9;i++)
        {
            a.a[i][0]=1;
            a.a[i][9]=i+1;
        }
        for(int i=1;i<9;i++)
        {
            a.a[i-1][i]=1;
            a.a[i+8][i+9]=1;
        }
        for(int i=9;i<18;i++)a.a[i][9]=10;
        while(n.compareTo(BigInteger.ZERO)>0)
        {
            if(n.mod(new BigInteger("2")).compareTo(BigInteger.ONE)==0)res=cla(a,res);
            a=cla(a,a);
            n=n.divide(new BigInteger("2"));
        }
        long d[]={128,64,32,16,8,4,2,1,1,23817625,2165227,196833,17891,1625,147,13,1,0};
        long ans=0;
        for(int i=0;i<18;i++)
        {
            ans+=(d[i]%MOD)*res.a[i][17]%MOD;
            ans%=MOD;
        }
        return ans;
    }
    public static void main(String args[])
    {
        Scanner cin=new Scanner(System.in);
        int T=cin.nextInt();
        while((T--)>0)
        {
            BigInteger a=cin.nextBigInteger();
            int b=cin.nextInt();
            MOD=cin.nextLong();
            System.out.println(POW(a.pow(b)));
        }
    }
}

Pro2 code:

#include <bits/stdc++.h>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
int n,q;
const int maxn=1e5+9;
const long long mod=1e9+7;

struct matrix
{
    long long m[3][3];
};
const matrix mp[2]= {{1,0,0,1,1,0,1,0,1},{1,1,0,0,1,0,0,1,1}};
matrix data[maxn<<2];
int f[maxn<<2];
char s[maxn];

matrix mul(matrix a,matrix b)
{
    matrix tmp;
    for(int i=0; i<3; i++)
    {
        for(int j=0; j<3; j++)
        {
            tmp.m[i][j]=0;
            for(int k=0; k<3; k++)
                tmp.m[i][j]+=(a.m[i][k]*b.m[k][j])%mod;
            tmp.m[i][j]%=mod;
        }
    }
    return tmp;
}
void flip(matrix &x)
{
    swap(x.m[0][0], x.m[0][1]);
    swap(x.m[1][0], x.m[1][1]);
    swap(x.m[2][0], x.m[2][1]);
    swap(x.m[0][0], x.m[1][0]);
    swap(x.m[0][1], x.m[1][1]);
}
void pushup(int rt)
{
    data[rt]= mul(data[rt<<1],data[rt<<1|1]);
}
void pushdown(int rt)
{
    if(f[rt])
    {
        flip(data[rt<<1]);
        flip(data[rt<<1|1]);
        f[rt<<1]^=f[rt];
        f[rt<<1|1]^=f[rt];
        f[rt]=0;
    }
}
void build(int l,int r,int rt)
{
    f[rt]=0;
    if(l==r)
    {
        int t=s[l]-'0';
        data[rt]=mp[t];
        return;
    }
    int m=r+l>>1;
    build(lson);
    build(rson);
    pushup(rt);
}
void update(int L,int R,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        f[rt]=1-f[rt];
        flip(data[rt]);
        return;
    }
    int m=l+r>>1;
    pushdown(rt);
    if(L<=m) update(L,R,lson);
    if(m<R) update(L,R,rson);
    pushup(rt);
}
matrix query(int L,int R,int l,int r,int rt)
{
    if(L==l&&r==R)
        return data[rt];
    int m=l+r>>1;
    pushdown(rt);
    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));
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&q);
        scanf("%s",s+1);
        build(1,n,1);
        while(q--)
        {
            int op,l,r;
            scanf("%d%d%d",&op,&l,&r);
            if(op==1)
                update(l,r,1,n,1);
            else
            {
                matrix x=query(l,r,1,n,1);
                printf("%I64d\n",(x.m[2][0]+x.m[2][1])%mod);
            }
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值