Codeforces-954F:Runner's Problem(矩阵快速幂+离散化)

F. Runner's Problem
time limit per test
4 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

You are running through a rectangular field. This field can be represented as a matrix with 3 rows and m columns. (i, j) denotes a cell belonging to i-th row and j-th column.

You start in (2, 1) and have to end your path in (2, m). From the cell (i, j) you may advance to:

  • (i - 1, j + 1) — only if i > 1,
  • (i, j + 1), or
  • (i + 1, j + 1) — only if i < 3.

However, there are n obstacles blocking your path. k-th obstacle is denoted by three integers aklk and rk, and it forbids entering any cell (ak, j) such that lk ≤ j ≤ rk.

You have to calculate the number of different paths from (2, 1) to (2, m), and print it modulo 109 + 7.

Input

The first line contains two integers n and m (1 ≤ n ≤ 1043 ≤ m ≤ 1018) — the number of obstacles and the number of columns in the matrix, respectively.

Then n lines follow, each containing three integers aklk and rk (1 ≤ ak ≤ 32 ≤ lk ≤ rk ≤ m - 1) denoting an obstacle blocking every cell (ak, j) such that lk ≤ j ≤ rk. Some cells may be blocked by multiple obstacles.

Output

Print the number of different paths from (2, 1) to (2, m), taken modulo 109 + 7. If it is impossible to get from (2, 1) to (2, m), then the number of paths is 0.

Example
input
Copy
2 5
1 3 4
2 2 3
output
2
思路:由于有障碍,可以将障碍的端点储存下来,左端记录为1,右端记录为-1,然后进行排序。对于每个端点,如果是1,则表示当前行有障碍,记录在sum数组中,即sum[i]++;如果是-1,sum[i]--。然后进行快速幂的时候,如果sum[i]不等于0,就说明该行有障碍,友矩阵就需要改变。由于是一段一段的转移,要用一个数记录上一次转移到了什么位置,每次转移的时候,从上一个位置转移到当前端点。
#include<bits/stdc++.h>
using namespace std;
const int MAX=1e6;
const int MOD=1e9+7;
const double PI=acos(-1);
typedef __int64 ll;
int sum[4];
ll a[3];//分别储存每行的方案数
struct data{ll b[3][3];};
struct lenka
{
    ll x,y,in;
}A[MAX];
int cmp(const lenka& p,const lenka& q){return p.y<q.y;}//对端点排序
data cla(const data& p,const data& q)
{
    data c;
    memset(c.b,0,sizeof c.b);
    for(int i=0;i<3;i++)
    {
        for(int j=0;j<3;j++)
        {
            for(int k=0;k<3;k++)
            {
                c.b[i][j]+=p.b[i][k]*q.b[k][j]%MOD;
                c.b[i][j]%=MOD;
            }
        }
    }
    return c;
}
void POW(ll n)
{
    data res,b;
    memset(res.b,0,sizeof res.b);
    memset(b.b,0,sizeof b.b);
    for(int i=0;i<3;i++)res.b[i][i]=1;
    for(int i=0;i<3;i++)
    {
        for(int j=0;j<3;j++)b.b[i][j]=(sum[j]==0);//根据当前行是否有障碍来确定友矩阵
    }
    b.b[0][2]=b.b[2][0]=0;
    while(n)
    {
        if(n&1)res=cla(b,res);
        b=cla(b,b);
        n/=2;
    }
    ll x=(a[0]*res.b[0][0]%MOD+a[1]*res.b[1][0]%MOD+a[2]*res.b[2][0]%MOD)%MOD;
    ll y=(a[0]*res.b[0][1]%MOD+a[1]*res.b[1][1]%MOD+a[2]*res.b[2][1]%MOD)%MOD;
    ll z=(a[0]*res.b[0][2]%MOD+a[1]*res.b[1][2]%MOD+a[2]*res.b[2][2]%MOD)%MOD;
    a[0]=x;
    a[1]=y;
    a[2]=z;//更新方案数
}
int main()
{
    ll n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        ll x,L,R;
        scanf("%I64d%I64d%I64d",&x,&L,&R);
        A[i].x=x-1;
        A[i].y=L-1;
        A[i].in=1;
        A[i+n].x=x-1;
        A[i+n].y=R;
        A[i+n].in=-1;
    }
    sort(A+1,A+2*n+1,cmp);
    memset(sum,0,sizeof sum);
    memset(a,0,sizeof a);
    a[1]=1;
    ll L=1;//记录一次更新到的位置
    for(int i=1;i<=2*n;i++)
    {
        POW(A[i].y-L);
        L=A[i].y;
        sum[A[i].x]+=A[i].in;
    }
    POW(m-L);
    cout<<a[1]%MOD<<endl;
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值