zoukankan      html  css  js  c++  java
  • Educational Codeforces Round 40 F. Runner's Problem

    Educational Codeforces Round 40 F. Runner's Problem

    题意:

    给一个$ 3 * m (的矩阵,问从)(2,1)$ 出发 走到 ((2,m)) 的方案数 (mod 1e9 + 7), 走的规则和限制如下:

    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.

    给出了$n $个限制 每个限制如下描述

    (a_i, l_i, r_i l_i <= r_i 1<=a_i <= 3) 表示第((a_i, l_i))((a_i, ri)) 都是不可走的

    (n <= 10000 , m <= 10^{18})

    思路:

    考察没有限制的情况, 写出转移矩阵做快速幂即可

    (egin{bmatrix} 1& 1 &0 \ 1& 1 &1 \ 0& 1 &1 end{bmatrix})

    那么给定了限制之后,其实就是转移矩阵在某一段内不会发生变化,处理出每一段做快速幂即可。

    最开始我处理每一段的方法有点傻逼,将所有的端点按左开右闭的方式排序,然后对于取出的每一段区间判断第1,2,3行在这段区间内是否有障碍,我采用了对每一行的障碍排序,再用指针的方式来判断是否有障碍。

    #include<bits/stdc++.h>
    #define LL long long
    #define P pair<int,int>
    using namespace std;
    const int mod = 1e9 + 7;
    vector<pair<LL,LL> > a[3];
    vector<pair<LL,int> >p;
    int n, x;
    LL m, l, r;
    struct MAT{
        int a[3][3];
        MAT operator*(const MAT &rhs){
            MAT ans;
            memset(ans.a, 0, sizeof(ans.a));
            for(int i = 0;i < 3;i++){
                for(int j = 0;j < 3;j++){
                    for(int k = 0;k < 3;k++){
                        ans.a[i][j] = (ans.a[i][j] + 1LL * a[i][k] * rhs.a[k][j] % mod) % mod;
                    }
                }
            }
            return ans;
        }
        MAT operator^(LL k){
            MAT ans, A = *this;
            for(int i = 0;i < 3;i++){
                for(int j = 0;j < 3;j++) ans.a[i][j] = (i == j?1:0);
            }
            for(;k;k >>= 1,A = A * A) if(k & 1) ans = ans * A;
            return ans;
        }
    }mat;
    
    int b[3][3];
    void init(){
        b[0][0] = b[0][1] = 1;
        b[1][0] = b[1][1] = b[1][2] = 1;
        b[2][1] = b[2][2] = 1;
        b[0][2] = b[2][0] = 0;
    }
    void gao(int row){
        for(int i = 0;i < 3;i++) mat.a[row][i] = 0;
    }
    int main()
    {
        init();
        cin>>n>>m;
        for(int i = 0;i < n;i++){
            scanf("%d%lld%lld",&x,&l,&r);
            a[x - 1].push_back(make_pair(l,r));
            p.push_back(make_pair(l - 1, 0));
            p.push_back(make_pair(r, 1));
        }
        p.push_back(make_pair(1,0));
        p.push_back(make_pair(m, 1));
        sort(p.begin(),p.end());
        p.erase(unique(p.begin(),p.end()),p.end());
    
        for(int i = 0;i < 3;i++) sort(a[i].begin(),a[i].end());
        
        LL mxr[3] = {1,1,1};
        LL ans[3] = {0,1,0};
        int now[3] = {0};
        l = p[0].first;
        for(int i = 1; i  < p.size();i++){
            r = p[i].first;
            memcpy(mat.a, b, sizeof(b));
            for(int j = 0;j < 3;j++){
                int &xx = now[j];
                while(xx < a[j].size() && a[j][xx].first <= l + 1 &&
                      (mxr[j] = max(a[j][xx].second,mxr[j])) < r) xx++;
                if(xx < a[j].size() && a[j][xx].first <= l + 1 && mxr[j] >= r){
                    gao(j);
                }
            }
    
            mat = mat ^ (r - l);
            LL tmp[3] = {0};
            for(int j = 0;j < 3;j++){
                for(int k = 0;k < 3;k++) {
                    tmp[j] += 1LL * mat.a[j][k] * ans[k] % mod;
                    tmp[j] %= mod;
                
            }
            memcpy(ans, tmp, sizeof(tmp));
            l = p[i].first;
        }
        cout<<ans[1]<<endl;
        return 0;
    }
    

    实际上存端点的时候 可以把该端点是起点还是终点以及在哪一行存进去,这样就可以单独每一行进行维护。

    当某一行遇到一个起点后,意味着该行从这个点开始都是有障碍的,直到遇到一个终点+1 后面才没有障碍,

    这样就容易判断的多。

    常用的区间标记操作,只是这里一时没有将这个知识用上来,以致于采用前面的做法觉得复杂很多。

    #include<bits/stdc++.h>
    #define LL long long
    #define P pair<int,int>
    using namespace std;
    const int mod = 1e9 + 7;
    int n, x;
    LL m, l, r;
    struct MAT{
        int a[3][3];
        MAT operator*(const MAT &rhs){
            MAT ans;
            memset(ans.a, 0, sizeof(ans.a));
            for(int i = 0;i < 3;i++){
                for(int j = 0;j < 3;j++){
                    for(int k = 0;k < 3;k++){
                        ans.a[i][j] = (ans.a[i][j] + 1LL * a[i][k] * rhs.a[k][j] % mod) % mod;
                    }
                }
            }
            return ans;
        }
        MAT operator^(LL k){
            MAT ans, A = *this;
            for(int i = 0;i < 3;i++){
                for(int j = 0;j < 3;j++) ans.a[i][j] = (i == j?1:0);
            }
            for(;k;k >>= 1,A = A * A) if(k & 1) ans = ans * A;
            return ans;
        }
    };
    struct node{
        LL x;
        int row, f;
        node(LL x,int row,int f):x(x),row(row),f(f){};
        bool operator<(const node&rhs)const{
            return x < rhs.x;
        }
    };
    vector<node> p;
    int main()
    {
    
        cin>>n>>m;
        for(int i = 0;i < n;i++){
            scanf("%d%lld%lld",&x,&l,&r);
            p.push_back(node(l, x - 1, 1));
            p.push_back(node(r + 1, x - 1, -1));
        }
        p.push_back(node(m + 1, 1, -1));
        sort(p.begin(),p.end());
        int isobstacle[4] = {0};
        MAT ans;
        for(int i = 0;i < 3;i++) for(int j = 0;j < 3;j++) ans.a[i][j] = (i == j?1:0);
        l = 1;
        for(int i = 0; i < p.size();i++){ 
            r = p[i].x;
            LL d = r - l - 1;  /// 区间左闭右开
            if(d){
                MAT mat;
                for(int i = 0;i < 3;i++){ // 初始化转移矩阵
                    for(int j = 0;j < 3;j++) {
                            if(!isobstacle[i] && abs(i - j) <= 1) mat.a[i][j] = 1;
                            else mat.a[i][j] = 0;
                    }
                }
                ans = (mat ^ d) * ans;
            }
            isobstacle[p[i].row] += p[i].f;
            l = r - 1;
        }
        cout<<ans.a[1][1]<<endl;
        return 0;
    }
    
    
  • 相关阅读:
    SmartPlant Review 渲染模块低性能设置
    由浅入深:Python 中如何实现自动导入缺失的库?(转)
    itchat初步解读登录(转)
    转:【开源必备】常用git命令
    2.转发。基于itchat的微信消息同步机器人
    1、初学探讨PYTHON的itchat和wxpy两库
    学习git 新手。这个写的不错
    常见的内置错误及处理
    面试题记录1
    防抖
  • 原文地址:https://www.cnblogs.com/jiachinzhao/p/8654053.html
Copyright © 2011-2022 走看看