zoukankan      html  css  js  c++  java
  • [hdu5411 CRB and Puzzle]DP,矩阵快速幂

    题意:给一个有向图,从任意点开始,最多走m步,求形成的图案总数。

    思路:令dp[i][j]表示走j步最后到达i的方法数,则dp[i][j]=∑dp[k][j-1],其中k表示可以直接到达i的点,答案=∑dp[i][j]。关键在于如何减少状态转移的时间,考虑用矩阵加速。

    构造矩阵:D = ,其中a[i][j]表示有向图,用于状态转移,右边的一列1用于累加答案

    则答案=[1,1,...1n+1]*DM-1=∑∑DM-1[i][j],1≤i≤n+1,1≤j≤n+1

    PS:封装的ModInt放矩阵的最里面进行运算比直接取模慢了3倍多,因此在性能瓶颈地方尽量用最快的写法

    #pragma comment(linker, "/STACK:10240000")
    #include <map>
    #include <set>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <queue>
    #include <stack>
    #include <vector>
    #include <cstdio>
    #include <string>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    #define X                   first
    #define Y                   second
    #define pb                  push_back
    #define mp                  make_pair
    #define all(a)              (a).begin(), (a).end()
    #define fillchar(a, x)      memset(a, x, sizeof(a))
    #define copy(a, b)          memcpy(a, b, sizeof(a))
    
    typedef long long ll;
    typedef pair<int, int> pii;
    typedef unsigned long long ull;
    
    #ifndef ONLINE_JUDGE
    void RI(vector<int>&a,int n){a.resize(n);for(int i=0;i<n;i++)scanf("%d",&a[i]);}
    void RI(){}void RI(int&X){scanf("%d",&X);}template<typename...R>
    void RI(int&f,R&...r){RI(f);RI(r...);}void RI(int*p,int*q){int d=p<q?1:-1;
    while(p!=q){scanf("%d",p);p+=d;}}void print(){cout<<endl;}template<typename T>
    void print(const T t){cout<<t<<endl;}template<typename F,typename...R>
    void print(const F f,const R...r){cout<<f<<", ";print(r...);}template<typename T>
    void print(T*p, T*q){int d=p<q?1:-1;while(p!=q){cout<<*p<<", ";p+=d;}cout<<endl;}
    #endif
    template<typename T>bool umax(T&a, const T&b){return b<=a?false:(a=b,true);}
    template<typename T>bool umin(T&a, const T&b){return b>=a?false:(a=b,true);}
    
    const double PI = acos(-1.0);
    const int INF = 1e9 + 7;
    const double EPS = 1e-12;
    
    /* -------------------------------------------------------------------------------- */
    
    const int maxn = 51;
    
    template<int mod>
    struct ModInt {
        const static int MD = mod;
        int x;
        ModInt(ll x = 0): x(x % MD) {}
        int get() { return x; }
    
        ModInt operator + (const ModInt &that) const { int x0 = x + that.x; return ModInt(x0 < MD? x0 : x0 - MD); }
        ModInt operator - (const ModInt &that) const { int x0 = x - that.x; return ModInt(x0 < MD? x0 + MD : x0); }
        ModInt operator * (const ModInt &that) const { return ModInt((long long)x * that.x % MD); }
        ModInt operator / (const ModInt &that) const { return *this * that.inverse(); }
    
        ModInt operator += (const ModInt &that) { x += that.x; if (x >= MD) x -= MD; }
        ModInt operator -= (const ModInt &that) { x -= that.x; if (x < 0) x += MD; }
        ModInt operator *= (const ModInt &that) { x = (long long)x * that.x % MD; }
        ModInt operator /= (const ModInt &that) { *this = *this / that; }
    
        ModInt inverse() const {
            int a = x, b = MD, u = 1, v = 0;
            while(b) {
                int t = a / b;
                a -= t * b; std::swap(a, b);
                u -= t * v; std::swap(u, v);
            }
            if(u < 0) u += MD;
            return u;
        }
    
    };
    typedef ModInt<2015> mint;
    
    int N;
    struct Matrix {
        int a[maxn][maxn];
    
        Matrix() {
            for (int i = 0; i < N; i ++) {
                for (int j = 0; j < N; j ++) {
                    a[i][j] = 0;
                }
            }
        }
    
        static Matrix unit() {
            Matrix ans;
            for (int i = 0; i < N; i ++) ans.a[i][i] = 1;
            return ans;
        }
    
        Matrix &operator * (const Matrix &that) const {
            static Matrix ans;
            for (int i = 0; i < N; i ++) {
                for (int j = 0; j < N; j ++) {
                    ans.a[i][j] = 0;
                    for (int k = 0; k < N; k ++) {
                        ans.a[i][j] += a[i][k] * that.a[k][j];
                        ans.a[i][j] %= 2015;
                    }
                }
            }
            return ans;
        }
    
        static Matrix power(Matrix a, int n) {
            Matrix ans = unit(), buf = a;
            while (n) {
                if (n & 1) ans = ans * buf;
                buf = buf * buf;
                n >>= 1;
            }
            return ans;
        }
    };
    
    class Timer {
    private:
        clock_t _start;
        clock_t _end;
    
    public:
        void init() {
            _start = clock();
        }
        void get() {
            _end = clock();
            cout << double(_end - _start) / CLK_TCK << endl;
        }
    };
    Timer clk;
    
    
    int main() {
    #ifndef ONLINE_JUDGE
        freopen("in.txt", "r", stdin);
        //freopen("out.txt", "w", stdout);
    #endif // ONLINE_JUDGE
        int T, n, m, k, x;
        cin >> T;
        while (T --) {
            cin >> n >> m;
            Matrix a;
            N = n + 1;
            for (int i = 0; i < n; i ++) {
                scanf("%d", &k);
                for (int j = 0; j < k; j ++) {
                    scanf("%d", &x);
                    a.a[i][-- x] = 1;
                }
            }
            for (int i = 0; i < N; i ++) a.a[i][N - 1] = 1;
            Matrix A = Matrix::power(a, m - 1);
            mint ans = 0;
            for (int i = 0; i < N; i ++) {
                for (int j = 0; j < N; j ++) {
                    ans += A.a[i][j];
                }
            }
            cout << ans.get() << endl;
        }
        return 0;
    }
    
  • 相关阅读:
    Linux常用命令
    Springboot环境搭建_第一个例子
    java 填写一个银行卡如何判断是否真实存在
    java 理解如何实现图片验证码 傻瓜都能看懂。
    编程语言学习路线··
    他他他她她她所唱所写………
    Docker 学习笔记 (4)
    Docker 学习笔记 (3)
    Docker 学习笔记 (2)
    Docker 学习笔记 (1)
  • 原文地址:https://www.cnblogs.com/jklongint/p/4746679.html
Copyright © 2011-2022 走看看