HDU 5411 CRB and Puzzle (矩陣快速冪水題)
阿新 • • 發佈:2018-12-20
#include<bits/stdc++.h> using namespace std; #define debug puts("YES"); #define rep(x,y,z) for(int (x)=(y);(x)<(z);(x)++) #define ll long long #define lrt int l,int r,int rt #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 #define root l,r,rt #define mst(a,b) memset((a),(b),sizeof(a)) const int maxn =50+5; const int mod=2015; const int ub=1e6; ll powmod(ll x,ll y){ll t; for(t=1;y;y>>=1,x=x*x%mod) if(y&1) t=t*x%mod; return t;} ll gcd(ll x,ll y){return y?gcd(y,x%y):x;} /* 題目大意:給定n個點,每個點都有個前繼關係, 就是說每個點後面可以連上k個點, 問利用這n個點組成的長度不超過m的序列數量是多少。 典型的矩陣快速冪格式, 先把要冪運算的矩陣構造出來, 不難發現這個狀態轉移矩陣就是每個點的前驅關係構成的, 其實就是張有向圖, 找好初始狀態,不難發現長度為1時候所有點數量均為1, 下面就是套路了,求快速冪的字首和是用構造矩陣的做法, 詳見程式碼。 */ ///矩陣結構 struct mat{ ll a[maxn][maxn]; int n; mat(int l=maxn-1){ memset(a,0,sizeof(a)); n=l; for(int i=1;i<=l;i++) a[i][i]=1;///初始化矩陣 } mat operator*(const mat& y) const{ mat ret; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++){ ret.a[i][j]=0; for(int k=1;k<=n;k++) (ret.a[i][j]+=1LL*a[i][k]*y.a[k][j]%mod)%=mod; } return ret; } }; mat quick_pow(mat x,ll n){mat ret;for(;n;n>>=1,x=x*x) if(n&1) ret=x*ret;return ret;} ll n,m,y; ll solve() { int k; mat x(n+1);memset(x.a,0,sizeof(x.a)); for(int i=1;i<=n;i++){ scanf("%d",&k); x.a[i][n+1]=1; for(int j=1;j<=k;j++) {scanf("%lld",&y);x.a[i][y]=1;} } if(m==0) return 1LL; x.a[n+1][n+1]=1; x=quick_pow(x,m); ll ans=0;for(int i=1;i<=n;i++) ans=(ans+x.a[i][n+1])%mod; return (ans+1)%mod; } int main() { int t;scanf("%d",&t); while(t--) { scanf("%lld%lld",&n,&m); printf("%lld\n",solve()); } return 0; }