zoukankan      html  css  js  c++  java
  • hdu 5411 CRB and Puzzle 矩阵高速幂

    链接

    题解链接:http://www.cygmasot.com/index.php/2015/08/20/hdu_5411/

    给定n个点 常数m

    以下n行第i行第一个数字表示i点的出边数。后面给出这些出边。

    问:图里存在多少条路径使得路径长度<=m。路径上的点能够反复。

    思路:

    首先能得到一个m*n*n的dp。dp[i][j]表示路径长度为i 路径的结尾为j的路径个数 。

    答案就是sigma(dp[i][j]) for every i from 1 to m, j from 1 to n;

    我们先计算 路径长度恰好为 i 的方法数。

    用矩阵高速幂,会发现是

     

    当中B矩阵是一个n*n的矩阵。也就是输入的邻接矩阵。

    A是一个n行1列的矩阵 A[i][1]表示长度为1且以i结尾的路径个数,所以A矩阵是全1矩阵。

    相乘得到的n*1 的矩阵求和就是路径长度恰好为i的条数。

    那么<=m的路径就是:


    把A提出来,里面就是一个关于B的矩阵等比数列。

    B的求发主要是二分。详见POJ3233

    模板不大好,交G++能过

    #pragma comment(linker, "/STACK:1024000000,1024000000")    
    #include<iostream>  
    #include<cstring>  
    #include<string>  
    #include<algorithm>  
    #include<cstdio>  
    #include<ctime>  
    
    using namespace std;
    template <class T>
    inline bool rd(T &ret) {
        char c; int sgn;
        if (c = getchar(), c == EOF) return 0;
        while (c != '-' && (c<'0' || c>'9')) c = getchar();
        sgn = (c == '-') ? -1 : 1;
        ret = (c == '-') ? 0 : (c - '0');
        while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0');
        ret *= sgn;
        return 1;
    }
    template <class T>
    inline void pt(T x) {
        if (x <0) {
            putchar('-');
            x = -x;
        }
        if (x>9) pt(x / 10);
        putchar(x % 10 + '0');
    }
    const int mod = 2015;
    const int N = 51;
    
    struct Matrix
    {
        int m[N][N];
    }G[2000];
    int top;
    Matrix I;
    int n, k;
    const int M = 2015;
    Matrix add(Matrix a, Matrix b)
    {
        Matrix &c = G[top++];
        for (int i = 0; i<n; i++)
        {
            for (int j = 0; j<n; j++)
            {
                c.m[i][j] = a.m[i][j] + b.m[i][j];
                c.m[i][j] %= M;
            }
        }
        top--;
        return c;
    }
    
    Matrix multi(Matrix a, Matrix b)
    {
        Matrix &c = G[top++];
        for (int i = 0; i<n; i++)
        {
            for (int j = 0; j<n; j++)
            {
                c.m[i][j] = 0;
                for (int k = 0; k<n; k++)
                    c.m[i][j] += a.m[i][k] * b.m[k][j];
                c.m[i][j] %= M;
            }
        }
        top--;
        return c;
    }
    
    Matrix power(Matrix A, int n)
    {
        Matrix &ans = G[top++], &p = G[top++];
        ans = I; p = A;
        while (n)
        {
            if (n & 1)
            {
                ans = multi(ans, p);
                n--;
            }
            n >>= 1;
            p = multi(p, p);
        }
        top -= 2;
        return ans;
    }
    
    Matrix sum(Matrix A, int k)
    {
        if (k == 1) return A;
        Matrix &t = G[top++];
        t = sum(A, k / 2);
        if (k & 1)
        {
            Matrix &cur = G[top++];
            cur = power(A, k / 2 + 1);
            t = add(t, multi(t, cur));
            t = add(t, cur);
            top--;
        }
        else
        {
            Matrix &cur = G[top++];
            cur = power(A, k / 2);
            t = add(t, multi(t, cur));
            top--;
        }
        top--;
        return t;
    }
    
    int m;
    void add(int &x, int y){
        x += y;
        if (x >= mod)x -= mod;
    }
    int B[N][N];
    int main(){
        memset(I.m, 0, sizeof I.m);
        for (int i = 0; i < N; i++)I.m[i][i] = 1;
        int T; rd(T);
        while (T--){
            rd(n); rd(m);
            Matrix A;
            top = 0;
            memset(A.m, 0, sizeof A.m);
            for (int i = 1; i <= n; i++) {
                int tmp; rd(tmp); while (tmp--) { int u; rd(u); A.m[i-1][u-1] = 1; }
            }
            if (m == 0) { puts("1"); continue; }
            if (m == 1){ pt(n + 1); puts(""); continue; }
            Matrix ans = sum(A, m-1);
            for (int i = 0; i<n; i++)
                for (int j = 0; j<n; j++)
                    B[i][j] = ans.m[i][j];
            
            for (int i = 0; i < n; i++)B[i][i] ++;
            int hehe = 0;
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                    add(hehe, B[i][j]);
            }
            pt(1 + hehe); puts("");
        }
        return 0;
    }
    /*
    99
    1 10
    1 1
    
    3 100000
    3 1 2 3
    3 1 2 3
    3 1 2 3
    
    5 3
    5 1 2 3 4 5
    4 2 3 4 5
    3 1 3 5
    5 1 2 3 4 5
    3 1 2 3
    
    */


  • 相关阅读:
    高斯消元学习
    HDU 4596 Yet another end of the world(解一阶不定方程)
    Codeforces Round #318 div2
    HDU 4463 Outlets(一条边固定的最小生成树)
    HDU 4458 Shoot the Airplane(计算几何 判断点是否在n边形内)
    HDU 4112 Break the Chocolate(简单的数学推导)
    HDU 4111 Alice and Bob (博弈)
    POJ 2481 Cows(线段树单点更新)
    HDU 4288 Coder(STL水过)
    zoj 2563 Long Dominoes
  • 原文地址:https://www.cnblogs.com/wzjhoutai/p/6936138.html
Copyright © 2011-2022 走看看