首页 > 其他分享 >P4159 [SCOI2009] 迷路

P4159 [SCOI2009] 迷路

时间:2023-06-10 17:03:00浏览次数:45  
标签:matrix 迷路 样例 int num SCOI2009 小点 P4159 节点

目录

题目链接


题目内容

[SCOI2009] 迷路

题目背景

windy 在有向图中迷路了。

题目描述

该有向图有 \(n\) 个节点,节点从 \(1\) 至 \(n\) 编号,windy 从节点 \(1\) 出发,他必须恰好在 \(t\) 时刻到达节点 \(n\)。

现在给出该有向图,你能告诉 windy 总共有多少种不同的路径吗?

答案对 \(2009\) 取模。

注意:windy 不能在某个节点逗留,且通过某有向边的时间严格为给定的时间。

输入格式

第一行包含两个整数,分别代表 \(n\) 和 \(t\)。

第 \(2\) 到第 \((n + 1)\) 行,每行一个长度为 \(n\) 的字符串,第 \((i + 1)\) 行的第 \(j\) 个字符 \(c_{i, j}\) 是一个数字字符,若为 \(0\),则代表节点 \(i\) 到节点 \(j\) 无边,否则代表节点 \(i\) 到节点 \(j\) 的边的长度为 \(c_{i, j}\)。

输出格式

输出一行一个整数代表答案对 \(2009\) 取模的结果。

样例 #1

样例输入 #1

2 2
11
00

样例输出 #1

1

样例 #2

样例输入 #2

5 30
12045
07105
47805
12024
12345

样例输出 #2

852

提示

样例输入输出 1 解释

路径为 \(1 \to 1 \to 2\)。

数据规模与约定

  • 对于 \(30\%\) 的数据,保证 \(n \leq 5\),\(t \leq 30\)。
  • 对于 \(100\%\) 的数据,保证 \(2 \leq n \leq 10\),\(1 \leq t \leq 10^9\)。

前置知识:矩阵快速幂

题目链接

一个幂数k=\(\sum2^i\) \(i\) \(\in\) \(Z\)
所以快速幂板子就出来啦()

#include<bits/stdc++.h>
using namespace std;

const int maxn=150;
const int m=1e9+7; 
typedef long long intx;

int n; 
intx k; 

struct matrix{
	intx num[maxn][maxn];
	matrix(){memset(num,0,sizeof(num));}
	void build(){for(int i=1;i<=n;++i)	num[i][i]=1;}	//单位矩阵 
};matrix a,ans;
matrix operator*(const matrix &x,const matrix &y){
	matrix z;
	for(int k=1;k<=n;++k){
		for(int i=1;i<=n;++i){
			for(int j=1;j<=n;++j){
				z.num[i][j]=(z.num[i][j]+x.num[i][k]*y.num[k][j]%m)%m;
			}
		}
	}
	return z;
}

void input(){
	scanf("%d%lld",&n,&k);
	for(int i=1;i<=n;++i){
		for(int j=1;j<=n;++j){
			scanf("%d",&a.num[i][j]);
		}
	}
}

int main(){
	input();
	ans.build();
	while(k){
		if(k&1)	ans=ans*a;
		a=a*a;
		k=k>>1;
	}
	for(int i=1;i<=n;++i){
		for(int j=1;j<=n;++j){
			printf("%d ",ans.num[i][j]);
		}
		printf("\n");
	}
	return 0;
}

私货:话题#虚拟歌姬也会迷路吗#

思路历程

1.我寻思这图里咋还有自环呢

对角线还有值这自己和自己连边啊。
干不会了。
然后就看这个专题名字叫“矩阵快速幂”
但是我还没有打过板子所以速速去打了一下()

2.ok快乐的板子时光总是短暂的()

我想了想觉得边权肯定是附加的属性,于是我先不管边权只建边或许可以的得到一些启发:
image

好丑的图()
嗯所以和矩阵有什么关系呢(其实当我画出这么多边的时候我就知道没什么用了)
怎么还越扯越远了()

3.额我们还是不看边权,但是不扯到图上去了。

如果,我是说如果,这是个邻接矩阵:
样例1:
1 1
0 0
问有几种到达方法。
那么就是说1要一个一个点到达2,第一行都要有数。
也就是说啊,i可以一个一个点的到达j,意味着\(a_i,_2\) ———— \(a_i,_j\)要有数
那经过的每一个点又都有一个出度,出度就是第i行1的个数
是不是说从1起点能到达的点的出度相乘再除以2就是方案数呢?
那么样例2呢:
1 1 0 1 1
0 1 1 0 1
1 1 1 0 1
1 1 0 1 1
1 1 1 1 1
怎么感觉不太对啊……
话说我要是从点1到点5再回点1再到点5这算不算一种方案啊……

4.那我们现在加上边权吧

那该怎么算边权呢?
我们假设边权只有1
\(f_t[i,j]\)表示从i点到j点花费时间为t的方案数
就有了方程:
\(f_t=\sum\limits_{k=1}^{n}f_{t-1}[i,k]+f_1[k,j]\)
那\(f_t\)也就是\(f_1^t\)。
那就出来了a。
\(f_1\)就是最初的矩阵啊。

5.回归本题

本题的区别在于权值是1-9啊
1-9,1-9……
我想了想,我他喵的\(f_t\)是\(f_1^t\)
那\(f_9\)不就是\(f_1^9\)吗!!!
那我把这个边多拆成几条边。
反正是求不小于t的方案数。
但是我如何建边才能保证没有多得方案数啊。
总不能搁节点1和节点2之间塞点吧
……
去看看题解()
……
我们1个点建9个小点,只有第0小点可以跨越小点的集合。
那么我们建立第i小点到第i-1小点的w=1的单向边
而要连的两个点1到点2则将小点集合1中的小点0和集合2中的小点w-1相连。
如下图(只画出了点1到点2经过的路径)
image
那么我们就转换成了边权都为1的9n*9n大小的矩阵。


代码实现:

注:与以上解释不同,代码中a[i][j]表示j指向i的边,并且不再设置第0小点改为设置第1小点为唯一可以外接点。

Miku's Code
#include<bits/stdc++.h>
using namespace std;

const int maxn=12;
const int mod=2009;

char s[maxn];
int n,sn,t;

struct matrix{
	int num[maxn*9][maxn*9];
	void clear(){
		memset(num,0,sizeof(num));
	}
	 
};matrix a;
matrix operator *(matrix x,matrix y){
	matrix res;
	res.clear();
	for(int k=1;k<=n;++k){
		for(int i=1;i<=n;++i){
			for(int j=1;j<=n;++j){
				res.num[i][j]=(res.num[i][j]+x.num[i][k]*y.num[k][j]%mod)%mod;
			}
		}
	}
	return res;
}

matrix operator ^(matrix x,int y){
	matrix res;
	res.clear();
	for(int i=1;i<=n;++i){
		res.num[i][i]=1;		//单位矩阵 
	}
	while(y){
		if(y&1)	res=res*x;
		x=x*x;
		y=y>>1;
	} 
	return res;
}

void inner_link(){				//小点间建边 
	for(int i=1;i<=sn;++i){
		for(int j=1;j<=8;++j){
			a.num[9*(i-1)+j][9*(i-1)+j+1]=1;
		}
	} 
}

void outer_link(){				//集合间建边 
	for(int i=1;i<=sn;++i){
		scanf("%s",s+1);
		for(int j=1;j<=sn;++j){
			if(s[j]>'0'){
				a.num[9*(i-1)+s[j]-'0'][9*(j-1)+1]=1;
			}
		}
	}
} 

int main(){
	scanf("%d%d",&n,&t);
	sn=n;
	n*=9;
	inner_link();
	outer_link();
	a=a^t;
	printf("%d",a.num[1][sn*9-8]);
	return 0;
}

标签:matrix,迷路,样例,int,num,SCOI2009,小点,P4159,节点
From: https://www.cnblogs.com/sonnety-v0cali0d-kksk/p/17471440.html

相关文章

  • 2023-5-21 #55 渐行渐远迷路的我 看向了光年外璀璨星河
    358P5897[IOI2013]wombats线段树维护矩阵乘法,注意到有决策单调性,复杂度\(O(nC^2\logn)\),但是空间过大,我们递归到一个较小的区间时暴力计算即可,若阈值为\(k\),空间会整体除\(k\)。359P8275[USACO22OPEN]262144RevisitedP先考虑一个序列的问题:答案显然不超过最大值\(......
  • P2657 [SCOI2009] windy 数 数位DP好题
    P2657[SCOI2009]windy数-洛谷|计算机科学教育新生态(luogu.com.cn)数位DP好题主要问题是:不含前导零且相邻两个数字之差至少为 2solution:现在枚举到了第i位......
  • 【转载】茅台巽风app地图详解,做任务不迷路,纯手绘
    茅台发布了新的app“巽风”根据“巽值”的排名,发放20000个虎年茅台的资格,还是可以玩一玩的哪些途径获取“巽值”1.做任务,和游戏里面的导师、村民聊天。完成他们交代的......
  • #yyds干货盘点# LeetCode程序员面试金典:迷路的机器人
    题目:设想有个机器人坐在一个网格的左上角,网格r行c列。机器人只能向下或向右移动,但不能走到一些被禁止的网格(有障碍物)。设计一种算法,寻找机器人从左上角移动到右下角的路......
  • P4159 [SCOI2009] 迷路
    \(P4159\)[\(SCOI2009\)]迷路题目传送门前序知识整理关键词:矩阵+快速幂P1226【模板】快速幂||取余运算矩阵乘法P3390【模板】矩阵快速幂P1939【模板】矩阵加......
  • P4158 [SCOI2009]粉刷匠
    题意:windy有N条木板需要被粉刷。每条木板被分为M个格子。每个格子要被刷成红色或蓝色。windy每次粉刷,只能选择一条木板上一段连续的格子,然后涂上一种颜色。每个格......
  • 做题记录整理dp11 P4158 [SCOI2009]粉刷匠(2022/9/23)
    P4158[SCOI2009]粉刷匠事实上前半个小时我甚至没想用dp做。。。感觉这道题难度标高了(跟那个想让我测出题人的码的题相比)首先可以发现每一行之间都是独立的,所以先考虑把......
  • 【线性dp】 [SCOI2009]粉刷匠
    点个关注点个赞吧一道比较简单的线性dp题目前置知识:会手推一些简单的状态转移方程、较为熟练地掌握背包问题模型[SCOI2009]粉刷匠题目描述windy有\(N\)条木......