zoukankan      html  css  js  c++  java
  • HH去散步

    题目link:https://www.luogu.com.cn/problem/P2151


    Part0:

    注意题目有重边。


    Part1:

    首先这道题的题目限制为走过一条边不能按原边返回,这就导致了这个图的有向性,从而得出需要拆边的结论。


    Part2:

    拆完边后,容易看出如果要想满足题目限制,那么相当于走过第 $i$ 条边后,除了 $i$ 的反向边都可以走。


    Part3:

    得到上述特性后,再来观察题目,发现数据范围里的 $m$ 的值比较小,且比较的特殊,但是注意,因为通过 Part1Part2 已经拆完边了,那么边的数量需要 $*$ $2$ 。

    众所周知,这道题要求的路径方案数和邻接矩阵的幂次方有很大的关系,再加上 $2$ $*$ $m$ $=$ $120$ 这个值,发现 $120^3$ $*$ $log$ $t$ (矩阵快速幂的复杂度为 $O($$n^3$ $log$ $k$$)$)约为 $5e7$ ,不会超时,因此考虑用 $2$ $*$ $m$ 为行列的大小建一个矩阵。


    Part4:

    建完矩阵后,容易发现矩阵中的元素的一种恰当且显然的意义为如果第 $i$ 条边的终点是第 $j$ 条边的起点 $&&$ 第 $i$ 条边和第 $j$ 条边不是反向边,那么矩阵中的第 $i$ 行第 $j$ 列的元素就是 $1$ ,否则为 $0$ 。


    Part5:

    考虑矩形的 $k$ 次方是什么含义,设 $k$ 次方之后的矩形为 $A$ ,那么容易得出 $A_{i, j}$ 是在图上第 $i$ 条边经过 $k$ $+$ $1$ 条边到达第 $j$ 条边(包括第 $i$ 条边和第 $j$ 条边)的方案数。


    Part6:

    这样,便容易得出求答案的方法为:在建完矩阵后用矩阵快速幂求出它的 $t$ $-$ $1$ 次方(注意不是 $t$ 次方),枚举起点 $a$ 的所有出边和终点 $b$ 的所有入边,累加计算一下就好了。


    Code:

      1 #include <cstdio>
      2 
      3 typedef long long LL;
      4 
      5 const int MAXM = 60;
      6 const LL MOD = 45989;
      7 
      8 int n, m, t, a, b;
      9 int outA[MAXM + 5], inB[MAXM + 5], cntA, cntB, cntEdge;
     10 
     11 struct Node {
     12     int st, to;
     13 };
     14 
     15 struct Mat {
     16 
     17     int N;
     18     LL arr[2 * MAXM + 5][2 * MAXM + 5];
     19 
     20     Mat() {}
     21     Mat(int _N, LL val = 0ll) {
     22         N = _N;
     23         for(int i = 1; i <= N; ++i) {
     24             for(int j = 1; j <= N; ++j) {
     25                 arr[i][j] = (i == j) ? val : 0ll;
     26             }
     27         }
     28     }
     29 
     30     // void print() {
     31     //     for(int i = 1; i <= N; ++i) {
     32     //         for(int j = 1; j <= N; ++j) {
     33     //             printf("%d%c", arr[i][j], (j == N - 1) ? '
    ' : ' ');
     34     //         }
     35     //     }
     36     //     puts("");
     37     // }
     38 
     39 };
     40 
     41 Mat operator* (const Mat &A, const Mat &B) {
     42 
     43     Mat res(A.N);
     44 
     45     for(int i = 1; i <= res.N; ++i) {
     46         for(int j = 1; j <= res.N; ++j) {
     47             for(int k = 1; k <= res.N; ++k) {
     48                 res.arr[i][j] += A.arr[i][k] * B.arr[k][j];
     49                 res.arr[i][j] %= MOD;
     50             }
     51         }
     52     }
     53 
     54     return res;
     55 }
     56 
     57 Mat qpow(Mat A, int k) {
     58 
     59     Mat res(A.N, 1ll);
     60 
     61     for(; k; k >>= 1) {
     62         if(k & 1) res = res * A;
     63         A = A * A;
     64     }
     65 
     66     return res;
     67 }
     68 
     69 int main() {
     70 
     71     scanf("%d %d %d %d %d", &n, &m, &t, &a, &b);
     72 
     73     Node edge[2 * MAXM + 5]; // 存边
     74     for(int i = 1, x, y; i <= m; ++i) {
     75         scanf("%d %d", &x, &y);
     76         edge[++cntEdge].st = x, edge[cntEdge].to = y;
     77         edge[++cntEdge].st = y, edge[cntEdge].to = x;
     78         if(x == a || y == a) { // 记录起点和终点的出边和入边
     79             outA[++cntA] = (x == a) ? cntEdge - 1 : cntEdge;
     80         }
     81         if(x == b || y == b) {
     82             inB[++cntB] = (x == b) ? cntEdge : cntEdge - 1;
     83         }
     84     }
     85 
     86     Mat fac(2 * m); // 建矩阵
     87     for(int i = 1; i <= cntEdge; ++i) {
     88         for(int j = 1; j <= cntEdge; ++j) {
     89             if(i == j || ((i & 1) && (j == i + 1)) || ((!(i & 1)) && (j == i - 1))) continue;
     90             if(edge[i].to == edge[j].st) {
     91                 fac.arr[i][j] = 1ll;
     92             }
     93         }
     94     }
     95     
     96     fac = qpow(fac, t - 1); // 矩阵快速幂
     97 
     98     LL ans = 0; // 枚举出入边求解
     99     for(int i = 1; i <= cntA; ++i) {
    100         for(int j = 1; j <= cntB; ++j) {
    101             ans += fac.arr[outA[i]][inB[j]];
    102             ans %= MOD;
    103         }
    104     }
    105 
    106     printf("%lld
    ", ans);
    107 
    108     return 0;
    109 }
  • 相关阅读:
    对html与body的一些研究与理解
    关于文字内容溢出用点点点(...)省略号表示
    CSS3中border-image属性详解
    从TCP协议的原理来谈谈rst复位攻击
    关于Oracle中sysoper这个系统权限的问题
    翻翻git之---有用的欢迎页开源库 AppIntro
    椒盐噪声
    Codeforces Beta Round #1 A. Theatre Square
    log4j:WARN Please initialize the log4j system properly解决的方法
    微信平台开发——日历服务
  • 原文地址:https://www.cnblogs.com/qqq1112/p/15072355.html
Copyright © 2011-2022 走看看