CF-Codeforces Round #420 (Div. 2)-E-Okabe and El Psy Kongroo

228 篇文章 1 订阅
174 篇文章 3 订阅

ACM模版

描述

描述
描述

题解

这个题是矩阵快速幂问题,给定若干个上界,每个上界都是有一定宽度的,这些上界在 x 轴的投影是连续的,要我们从 (0,0) 移动到 (k,0) ,每次只能向右、右上、右下移动,所以呢,这个其实和 《机器人走方格》有些相似,不过他是给定了连续的若干个矩形区域(每个上界和 x 轴之间的区域),需要求这些区域合并在一起后的方案数,另外这里我们的 k 是很大的,所以必须使用矩阵快速幂了。

因为上界最大为 15 ,所以我们需要构造一个 1616 的矩阵进行快速幂,这个矩阵的样子大概是酱紫的:

A=1100000111000001110000011000000011000001110000011

这也是本题的核心,构造出来这个矩阵,也就好写多了……

剩下的就看看代码吧,没有什么稀奇古怪的了,注意数据类型。

代码

#include <cstdio>
#include <cstring>

#define mod(x) ((x) % MOD)

using namespace std;

typedef long long ll;

const ll MOD = 1e9 + 7;
const int MAX_MAT_SIZE = 16;

typedef struct Matrix
{
    ll m[MAX_MAT_SIZE][MAX_MAT_SIZE];
} mat;

mat A, B, pre, unit;

mat matrix_mul(mat a, mat b, int len)
{
    mat ret;
    memset(ret.m, 0, sizeof(ret.m));

    for (int k = 0; k <= len; k++)
    {
        for (int i = 0; i <= len; i++)
        {
            if (a.m[i][k])
            {
                for (int j = 0; j <= len; j++)
                {
                    ret.m[i][j] = mod(ret.m[i][j] + (ll)a.m[i][k] * b.m[k][j]);
                }
            }
        }
    }
    return ret;
}

void init()
{
    memset(A.m, 0, sizeof(A.m));
    for (int i = 0; i < MAX_MAT_SIZE; i++)
    {
        for (int j = i - 1; j < i + 2 && j < MAX_MAT_SIZE; j++)
        {
            if (j >= 0)
            {
                A.m[i][j] = 1;
            }
        }
    }

    memset(unit.m, 0, sizeof(unit.m));
    for (ll i = 0; i < MAX_MAT_SIZE; i++)
    {
        unit.m[i][i] = 1;
    }

    memset(pre.m, 0, sizeof(pre.m));
    pre.m[0][0] = 1;
}

Matrix matrix_quick_power(mat a, ll k, int len)
{
    mat ret = unit;

    while (k)
    {
        if (k & 1)
        {
            ret = matrix_mul(a, ret, len);
        }
        a = matrix_mul(a, a, len);
        k >>= 1;
    }

    return ret;
}

int n;
ll k;

int main()
{
    init();

    scanf("%d%lld", &n, &k);

    ll a, b;
    int c, flag = 0;
    for (int i = 1; i <= n; i++)
    {
        scanf("%lld%lld%d", &a, &b, &c);
        if (b > k)
        {
            b = k;
            flag = 1;
        }
        B = matrix_quick_power(A, b - a, c);
        for (int j = c + 1; j < MAX_MAT_SIZE; j++)
        {
            pre.m[j][0] = 0;
        }
        B = matrix_mul(B, pre, c);

        for (int j = 0; j <= c; j++)
        {
            pre.m[j][0] = B.m[j][0];
        }
        if (flag == 1)
        {
            break;
        }
    }

    printf("%lld\n", B.m[0][0]);

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值