BZOJ 1297: [SCOI2009]迷路 [矩阵快速幂]

Description

windy在有向图中迷路了。 该有向图有 N 个节点,windy从节点 0 出发,他必须恰好在 T 时刻到达节点 N-1。 现在给出该有向图,你能告诉windy总共有多少种不同的路径吗? 注意:windy不能在某个节点逗留,且通过某有向边的时间严格为给定的时间。

Input

第一行包含两个整数,N T。 接下来有 N 行,每行一个长度为 N 的字符串。 第i行第j列为‘0‘表示从节点i到节点j没有边。 为‘1‘到‘9‘表示从节点i到节点j需要耗费的时间。

Output

包含一个整数,可能的路径数,这个数可能很大,只需输出这个数除以2009的余数。

Sample Input

【输入样例一】
2 2
11
00

【输入样例二】
5 30
12045
07105
47805
12024
12345

Sample Output

【输出样例一】
1

【样例解释一】
0->0->1

【输出样例二】
852

HINT

30%的数据,满足 2 <= N <= 5 ; 1 <= T <= 30 。
100%的数据,满足 2 <= N <= 10 ; 1 <= T <= 1000000000 。

思路:矩阵快速幂应该是第一个能想到的,但是直接将一个长为9的边拆成9个点,那最坏情况下就有9*9*9个点约等于700多个点,时间复杂度是n*n*n*log(t)前面显然会爆,但是可以这样,把一个点拆成9个点,9个点连成一条链,这样就可以乱搞了,如果一个点x到这个点y有长度为k的边 只要将x连到y前面k-1个点就行(因为连出一条边就减少了一条边)

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #define N 90
 5 #define MOD 2009
 6 using namespace std;
 7 char ch[100][100];
 8 struct mat
 9 {
10     long long m[N+1][N+1];
11     mat(){memset(m,0,sizeof(m));}
12 };
13 mat operator *(mat a,mat b)
14 {
15     mat ans;
16     for(int i=1;i<=N;i++)
17     {
18         for(int j=1;j<=N;j++)
19         {
20             for(int k=1;k<=N;k++)
21             {
22                 ans.m[i][j] = (ans.m[i][j] + a.m[i][k] * b.m[k][j])% MOD;
23             }
24         }
25     }
26     return ans;
27 }
28 mat pow(mat a,long long n)
29 {
30     mat ret;
31     for(int i=1;i<=N;i++)ret.m[i][i]=1;
32     for(;n;n>>=1)
33     {
34         if(n&1)ret = (ret * a);
35         a = (a*a);
36     }
37     return ret;
38 }
39 int main()
40 {
41     int n,t;
42     mat a;
43     scanf("%d%d",&n,&t);
44     for(int i=1;i<=n;i++)
45     {
46         scanf("%s",ch[i]+1);
47     }
48     for(int i=1;i<=n;i++)
49     {
50         for(int j=1;j<=8;j++)
51         {
52             a.m[(i-1)*9+j][(i-1)*9+j+1]=1;
53         }
54     }
55     for(int i=1;i<=n;i++)
56     {
57         for(int j=1;j<=n;j++)
58         {
59             int u = ch[i][j]-‘0‘;
60             if(u!=0)
61             {
62                 a.m[(i-1)*9+9][(j-1)*9+(9-u+1)]=1;
63             }
64         }
65     }
66     a = pow(a,t);
67     printf("%lld\n",a.m[9][(n-1)*9+9]);
68     return 0;
69 }
时间: 2024-08-28 10:14:17

BZOJ 1297: [SCOI2009]迷路 [矩阵快速幂]的相关文章

BZOJ 1297 SCOI2009 迷路 矩阵乘法

题目大意:给定一个邻接矩阵,求1~n的边权恰好为T的路径条数 考虑当所有边权都是1的时候 那么显然邻接矩阵自乘T次之后a[1][n]就是答案 因为当边权为1的时候a[i][j]可以表示从第i个点转移到第j个点的方案数 显然这个符合矩乘的定义 现在边权最大为9 那么将一个点拆成9个 第i个点拆成的第j+1个点向第j个点连一条边权为1的边 那么i->j有一条边权为k的边等价于i向j拆成的第k个点连边 #include <cstdio> #include <cstring> #in

矩阵乘法专题1——bzoj 1297 [SCOI2009] 迷路题解

题目链接 题意:给两个长度分别为n和m的序列,现在有两种操作:1.分别选择两个序列的一个非空前缀,切两个前缀的最后一位相同,删除之,得到1分(只累计),消耗e:2.直接删除两个序列,消耗值定于两个序列之前删除的元素个数之和,并且使得得到的分有效(之前没有有效分) 分析: 首先,问题其实就是转化成,进行若干次操作1,然后进行操作2 还要找到一个判别标准,来评判较优的状态(贪心) 每次的消耗值比较大,其实可以计算出最大的删除次数,这个值不是很大 状态表示: 简单的,一个状态可以表示为串A的位置.串B

BZOJ 1297 迷路(矩阵快速幂)

很容易想到记忆化搜索的算法. 令dp[n][T]为到达n点时时间为T的路径条数.则dp[n][T]=sigma(dp[i][T-G[i][n]]); 但是空间复杂度为O(n*T),时间复杂度O(n*n*T). 虽然本题的n<=10,但T最大可到1e9.行不通. 如果题目中的边的权值非0即1的话,显然1-n的长度为T的路径中数为 该图的邻接矩阵的T次幂. 实际上题目中的边权值<10. 可以用拆点的方法转化为边权值非0即1的情况. 即 将图中的每个点拆成至多9个点,首先将每个点的第i个点和第i+1

[BZOJ 1297][SCOI2009]迷路

1297: [SCOI2009]迷路 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1418  Solved: 1017[Submit][Status][Discuss] Description windy在有向图中迷路了. 该有向图有 N 个节点,windy从节点 0 出发,他必须恰好在 T 时刻到达节点 N-1. 现在给出该有向图,你能告诉windy总共有多少种不同的路径吗? 注意:windy不能在某个节点逗留,且通过某有向边的时间严格为给定

BZOJ 2510: 弱题( 矩阵快速幂 )

每进行一次, 编号为x的数对x, 和(x+1)%N都有贡献 用矩阵快速幂, O(N3logK). 注意到是循环矩阵, 可以把矩阵乘法的复杂度降到O(N2). 所以总复杂度就是O(N2logK) ---------------------------------------------------------------------- #include<bits/stdc++.h> using namespace std; const int maxn = 1009; int N, M, K,

bzoj1297 [SCOI2009]迷路——拆点+矩阵快速幂

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1297 一看感觉是矩阵快速幂之类的,但边权不好处理啊: 普通的矩阵快速幂只能处理边权为1的,所以想办法把边权处理成1: 仔细一看还有一个条件是边权小于10: 所以拆点!把一个点拆成10个点表示到它不同的距离,那么和它相连的那些点就可以跟某个距离的点连边权为1的边: 虽然没有自己想出来,不过1A还是极好的!(因为太简单了) 代码如下: #include<iostream> #include&

BZOJ 2875: [Noi2012]随机数生成器( 矩阵快速幂 )

矩阵快速幂...+快速乘就OK了 -------------------------------------------------------------------------------------- #include<bits/stdc++.h> using namespace std; typedef long long ll; ll MOD, a, c, x, n, g; ll MUL(ll a, ll b) { ll ans = 0; for(; b; b >>= 1

[BZOJ 2875][NOI 2012]随机数生成器(矩阵快速幂)

题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=2875 题目居然没给描述,我特么真无语了...好吧我来发个题目描述: 给出a,c,g,mod,x0,n,xn=(a*xn-1+c)%mod,求xn%g 联想用矩阵快速幂在logn的复杂度下求斐波那契数列,对这题我们也可以采取类似的方法. 我们用矩阵运算来改装这个递推式: 设 那么 于是可以直接用矩阵快速幂求A矩阵的n次方,然后再乘上x0即可得出xn 此题还有两个坑点: 1.xn求出

bzoj(矩阵快速幂)

题意:定义Concatenate(1,N)=1234567……n.比如Concatenate(1,13)=12345678910111213.给定n和m,求Concatenate(1,n)%m. (1=<n<=10^18,1<=m<=10^9) 思路:令f[n]表示Concatenate(1,n).那么有: f[i]=f[i-1]*10+(i-1)+1   1<=i<=9 f[i]=f[i-1]*100+(i-1)+1  10<=i<=99 …… 因此可用矩