• BZOJ1297 [SCOI2009]迷路 【矩阵优化dp】


    题目

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

    输入格式

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

    输出格式

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

    输入样例

    5 30

    12045

    07105

    47805

    12024

    12345

    输出样例

    852

    提示

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

    题解

    (f[i][t])表示(t)时刻到达(i)号点的方案数
    那么有

    [f[i][t] = sumlimits_{e(j,i) in edge} f[j][t - e.w] ]

    (T)很大,而且显然这是一个齐次式,考虑矩阵优化
    但是矩阵优化只能一层层递推,这里边权的限制使我们可能跨多层

    发现边权很小,考虑拆点
    每个点拆成一长条链,分别管辖各种权值的出边
    这样就可以矩阵优化了

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #define LL long long int
    #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
    using namespace std;
    const int maxn = 95,maxm = 100005,INF = 1000000000,P = 2009;
    inline int read(){
    	int out = 0,flag = 1; char c = getchar();
    	while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
    	while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    	return out * flag;
    }
    struct Matrix{
    	int s[maxn][maxn],n,m;
    	Matrix(){n = m = 0; memset(s,0,sizeof(s));}
    }F,A;
    inline Matrix operator *(const Matrix& a,const Matrix& b){
    	Matrix ans;
    	if (a.m != b.n) return ans;
    	ans.n = a.n; ans.m = b.m;
    	for (int i = 1; i <= ans.n; i++)
    		for (int j = 1; j <= ans.m; j++)
    			for (int k = 1; k <= a.m; k++)
    				ans.s[i][j] = (ans.s[i][j] + a.s[i][k] * b.s[k][j] % P) % P;
    	return ans;
    }
    inline Matrix operator ^(Matrix a,int b){
    	Matrix ans; ans.n = ans.m = a.n;
    	REP(i,ans.n) ans.s[i][i] = 1;
    	for (; b; b >>= 1,a = a * a)
    		if (b & 1) ans = ans * a;
    	return ans;
    }
    int n,T;
    char s[maxn];
    int main(){
    	n = read(); T = read();
    	A.n = A.m = 9 * n;
    	REP(i,n){
    		scanf("%s",s + 1);
    		REP(j,n){
    			if (s[j] != '0'){
    				int d = s[j] - '0';
    				A.s[(j - 1) * 9 + 1][(i - 1) * 9 + d] = 1;
    			}
    		}
    		for (int j = 2; j <= 9; j++)
    			A.s[(i - 1) * 9 + j][(i - 1) * 9 + j - 1] = 1;
    	}
    	F.n = 9 * n; F.m = 1;
    	F.s[1][1] = 1;
    	Matrix Ans = (A^T) * F;
    	printf("%d
    ",Ans.s[(n - 1) * 9 + 1][1]);
    	return 0;
    }
    
    
  • 相关阅读:
    [USACO18OPEN]Talent Show
    Linux关机、重启命令
    [SHOI2014]概率充电器
    mount新磁盘
    [JLOI2012]时间流逝
    创建、删除swap分区
    牛客网NOIP赛前集训营-普及组(第二场)
    从show slave status 中1062错误提示信息找到binlog的SQL
    [USACO18OPEN]Out of Sorts P 冒泡排序理解之二
    ORA-28040: No matching authentication protocol
  • 原文地址:https://www.cnblogs.com/Mychael/p/8885490.html
Copyright © 2020-2023  润新知