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
    
    */


  • 相关阅读:
    spark 程序 TopN FileSort SecondarySort 的出错解决办法
    预报温度和体感温度不是一回事
    搜索引擎 搜索技巧
    scrapy 爬虫框架
    scala-sbt
    英语削笔机
    php 一句话木马
    [CS充实之路] CS50 WEEK 1
    UBUNTU 16.04 编译 OPENJDK8
    使用logrotate分割Tomcat的catalina日志
  • 原文地址:https://www.cnblogs.com/wzjhoutai/p/6936138.html
Copyright © 2011-2022 走看看