[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; }