【问题描述】
因为 SJY 干的奇怪事情过多,SJY 收到了休假的通知,于是他准备在都市间
来回旅游。SJY 有一辆车子,一开始行驶性能为 0,每过 1 时间行驶性能就会提
升 1 点。每个城市的道路都有性能要求。SJY 一共有 t 时间休息,一开始他位于
1 号城市(保证 1 号城市道路要求为 0),他希望在 n 号城市结束旅程。每次穿过
一条城市间的路会花费 1 时间, 当然他也可以停留在一个城市不动而花费 1 时间。
当且仅当车子的行驶性能大于等于一个城市, 我们才能到达那里。 SJY 希望知道,
旅游的方案模 10086 后的答案。(只要在某一时刻通过的道路存在一条不相同,
就算不同的方案)
【输入】
第一行三个数 n,m,t,表示有 n 个城市 m 条道路 t 时间。
第二行 n 个数,hi 表示第 i 个城市的道路性能要求。
第三到 m+2 行,每行两个数 u,v,表示城市 u 与城市 v 之间有一条单向道路
连接(可能有重边)。
【输出】
包括一个数字,表示旅游的方案模 10086。
【输入输出样例】
travel.in travel.out
5 17 7
0 2 4 5 3
1 2
2 1
1 3
3 1
1 4
4 1
4 5
5 4
5 3
4 1
2 1
5 3
2 1
2 1
1 2
2 1
1 3
245
第 5 页 共 6 页
【数据规模和约定】
对于 20%的数据,n<=10,t<=80;
对于 50%的数据,n<=30,t<=80;
对于 100%的数据,n<=70,m<=1000,t<=100000000,hi<=70。
题解:
首先一个二维的dp就可以搞出来,就是设dp[i][j],表示处于i节点,已经用了j天的方案数,转移十分显然,能否走或者停留到原点,所以dp[i][j]=dp[i][j-1],dp[i][j]+=dp[to][j-1],这个to,是反边的儿子节点,就是说可以从to转移到i来。这个只能有50分,记忆化搜索跑的十分快。
但我们注意到t太大了,根本开不下,所以我们思考,因为城市的限制很小,所以一旦大于71,后面的转移就不用考虑车子了,所以前面的71可以用dp处理出来,后面的我们可以用矩阵快速幂来优化。
首先,初始矩阵s[i][j],表示第72天i到j的方案数,然后转移矩阵k[i][j],表示i~j的路径数,然后乘起来就对了,但为什么是对的呢?其实本质就是一个floyed和乘法原理求方案数。
代码:
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <cmath> #include <iostream> #define MAXN 100 #define mod 10086 #define MAXN2 1000000 using namespace std; struct zhen{ int w[MAXN][MAXN]; zhen(){ memset(w,0,sizeof(w)); } }; int c[MAXN][MAXN],ask[MAXN],dp[MAXN][MAXN]; int n,m,t; void work(){ dp[1][0]=1; for(int t=0;t<=80;t++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(t+1>=ask[j]) dp[j][t+1]+=dp[i][t]*c[i][j],dp[j][t+1]%=mod; return; } zhen jvchen(zhen x,zhen y){ zhen z; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) for(int k=1;k<=n;k++) z.w[i][j]+=x.w[i][k]*y.w[k][j],z.w[i][j]%=mod; return z; } int main(){ scanf("%d%d%d",&n,&m,&t); for(int i=1;i<=n;i++) scanf("%d",&ask[i]),c[i][i]++; for(int i=1;i<=m;i++){ int x,y;scanf("%d%d",&x,&y); c[x][y]++; } work(); if(t<=79){ printf("%d",dp[n][t]); return 0; } zhen star,zhuan; for(int i=1;i<=n;i++){ star.w[i][i]=dp[i][80]; for(int j=1;j<=n;j++) zhuan.w[i][j]=c[i][j]; } t-=80; while(t){ if(t&1) star=jvchen(star,zhuan); zhuan=jvchen(zhuan,zhuan);t>>=1; } int ans=0; for(int i=1;i<=n;i++) ans+=star.w[i][n],ans%=mod; printf("%d",ans); return 0; }