codeforces 593E(矩阵类题目)

本文介绍了一种使用矩阵快速幂解决人从起点到终点所有可行路径数量的问题的方法。考虑到地图大小和时间序列操作,包括猫出现、消失及查询路径数,通过构建转移矩阵并利用快速幂优化计算。

给定一个R * C不超过20的图,一开始人在(1,1)然后给出之多100000个时间序列(按时间递增给出),

每个时间可能发生的事情是在某个位置出现猫(有猫的地方人不能存在),猫在某个位置消失,询问人从1,1点在1时刻出发在t时刻可以走到(x , y)的所有可行性路径数目。

分析:

典型的矩阵转移题目。

初始时用一个人d[ i ][ j]....代表人从1,1出发走了当前步数,可以走到1的路径数为i,走到2的路径数目为j,.......

那么转移矩阵 m[ ][ ] 代表的是从i - > j的所有可行路经数目,中间加上矩阵快速幂即可。

#include <bits/stdc++.h>

#define fst first
#define snd second
#define ALL(a) a.begin(), a.end()
#define clr(a, x) memset(a, x, sizeof a)
#define rep(i,x) for(int i=0;i<(int)x;i++)
#define rep1(i,x,y) for(int i=x;i<=(int)y;i++)
#define LOGN  22
typedef long long ll;
using namespace std;

const int mod = 1e9 + 7;
struct Matrix{
   int m[22][22];
   void standard(int n){
       rep(i,n) rep(j,n) m[i][j]=(i==j);
   }
   void show(int n){
       rep(i,n){
          rep(j,n) cout<<m[i][j]<<" ";
          cout<<endl;
       }
   }
};
int n;
Matrix mul(Matrix A,Matrix B){
    Matrix C;
    rep(i,n) rep(j,n){
       C.m[i][j] = 0;
       rep(k,n) C.m[i][j] =(C.m[i][j] + (ll)A.m[i][k]*B.m[k][j]%mod)%mod;
    }
    return C;
}
Matrix pow_(Matrix A,int c){
    Matrix ret ; ret.standard(n);
    while(c > 0){
        if(c & 1) ret=mul(ret,A);
        A=mul(A,A);
        c>>=1;
    }
    return ret;
}
const int dx[]={-1 , 0 ,1, 0};
const int dy[]={ 0 , 1 ,0,-1};
int r , c , q;
int main()
{
   scanf("%d %d %d",&r,&c,&q);
   n = r * c;
   Matrix A; A.standard(n);
   rep(i , r) rep(j , c){
       rep(d , 4){
           int ni = i + dx[d] , nj = j + dy[d];
           if(ni>=0 && ni < r && nj >= 0 && nj < c)
             A.m[i*c + j][ni*c+nj]=1;
       }
   }
   Matrix all , now; all.standard(n);
   int pret = 1 , vis[22]={0};
   while(q--){
      int cmd,x,y,t;
      scanf("%d %d %d %d",&cmd,&x,&y,&t),--x,--y;
      rep(i , n) rep(j , n){
              if(!vis[i] && !vis[j]) now.m[i][j] = A.m[i][j];
              else now.m[i][j] = 0;
      }
      all = mul(all , pow_(now , t - pret));
      pret = t;
      if(cmd == 2) vis[x*c + y] = 1;
      else if(cmd == 3)vis[x*c + y] = 0;
      else if(cmd == 1) printf("%d\n",all.m[0][x*c + y]);
   }
   return 0;
}

 
### CodeForces 平台上关于传递闭包的概念及其实现 #### 传递闭包定义 在一个有向图 \( G=(V,E) \) 中,如果存在一条从顶点 \( u \) 到顶点 \( v \) 的路径,则认为 \( u \) 可达于 \( v \)[^1]。传递闭包是指通过某种方式使得所有可达关系显式表示出来的新图。 #### Floyd-Warshall算法用于计算传递闭包 Floyd-Warshall是一种经典的多源最短路算法,在此可以用来构建传递闭包矩阵。该方法基于动态规划的思想,时间复杂度为\( O(n^3) \),其中\( n \) 是节点数量。具体来说: ```cpp const int MAXN = 105; bool graph[MAXN][MAXN]; // 初始化为false void floyd_warshall(int n){ for (int k = 0; k < n; ++k) for (int i = 0; i < n; ++i) for (int j = 0; j < n; ++j) graph[i][j] |= (graph[i][k] && graph[k][j]); } ``` 这段代码遍历所有的中间结点`k`,并更新每一对结点之间的连通状态。当发现可以通过某个中间结点到达另一结点时,就标记相应的位为真。 #### 应用场景——二分图匹配中的最长反链寻找 在某些题目中,比如Codeforces 590E Birthday问题里提到的方法之一就是先求解传递闭包再利用二分图的最大独立集来找到最长反链[^4]。这通常涉及到将原图转换成其对应的传递闭包版本,之后按照特定策略进行匹配操作找出符合条件的结果集合。 #### 使用Bitset优化枚举过程 考虑到效率问题,在处理大规模数据结构下的传递闭包运算时可采用bitset来进行快速逻辑运算。例如,在HDU 6496题目的分析部分描述了一种使用bitset加速交点判断的技术[^2]。这种方法能够显著减少不必要的重复计算量,从而提高整体性能表现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值