先说一句,矩阵真是太强了,啥玩意都能干。这个题是真的牛逼,做完我仿佛都变成了一个矩阵。
题意简述
给定一个图, ,用邻接矩阵给出,每条边的权值是 之间的整数( 表示边权, 表示不连通)。请你求出从 到 走边权和为 的路径数。
思路
拆点。每个点能联通的只有 种边权,所以拆成 个点,拆成的点之间大的往小的连边,建出来一个$ 9n\times 9n t (1,n)$位置的就是答案了。
具体的思维过程
- 如果我们的图边权是 ,那么该如何做呢?
- 如何把我们的图转化成1. 中那个图呢?
step.1 只有0,1的问题
设矩阵 中的 位置表示:从 到 边权和为 的情况数。那么 应该就等于初始给定的邻接矩阵。
转移方程:枚举中转点 , =
然后我们发现,这 不就是 么(矩阵乘法)。如果还有一点数学基础(或者你没有,但是你对前缀和很熟悉),你会发现,这个式子很容易推出通项
所以,在只有 的图中,我们只要把邻接矩阵看成一个数学上的矩阵,拿矩阵快速幂求一下 次方即珂。然后位于 位置的数就是从 到 边权和为 的方案数了。
step.2 转化
我们发现边权只有
种,其中联通的还只有
种,所以我们把每个点拆成
个点。设
表示点
拆出来的第
个点。为了节省空间,我们令
是
到
中的整数(虽然理论上它应该是
到
中的整数)。(看到
珂别想歪了,我还少一个
和一个
)。
然后我们还要转换边权。对于同一个 ,我们令 到 之间连一条权为 的边。对于 之间一条边权为 的边,那就只要从 往 之间连一条权为 的边即珂。我们发现,经过我们刚刚建的那些辅助边, 到 之间的间接距离就是 ,而且我们现在只用了权为 和 的边。(虽然我说的只有权为 的边,但是我没有加上去的边权就是 )。
然后现在我们的图由于拆点,就变成了只有 和 边权的边了。套用刚刚的方法即珂。
具体实现的注意事项
- 别忘了膜
- 拆点的转化公式: ,所以空间复杂度
- 开
代码:
#include<bits/stdc++.h>
using namespace std;
namespace Flandre_Scarlet
{
#define int long long
#define mod 2009
#define F(i,l,r) for(int i=l;i<=r;++i)
#define D(i,r,l) for(int i=r;i>=l;--i)
#define Fs(i,l,r,c) for(int i=l;i<=r;c)
#define Ds(i,r,l,c) for(int i=r;i>=l;c)
#define Tra(i,u) for(int i=G.Start(u),__v=G.To(i);~i;i=G.Next(i),__v=G.To(i))
#define MEM(x,a) memset(x,a,sizeof(x))
#define FK(x) MEM(x,0)
class Matrix//square matrix
{
#define N 112//changeable
private:
int a[N][N];
public:
//variable list
int n;//size
//initialization
Matrix()
{
memset(a,0,sizeof(a));
n=0;
}
Matrix(int _n)
{
memset(a,0,sizeof(a));
n=_n;
}
Matrix(int _n,int _x)
{_x%=mod;
n=_n;
for(int i=0;i<N;++i)
{
for(int j=0;j<N;++j)
{
a[i][j]=_x;
}
}
}
//get value
int* operator[](int i)
{
return *(a+i);
}
//set value
void Set(int x)
{x%=mod;
for(int i=0;i<N;++i)
{
for(int j=0;j<N;++j)
{
a[i][j]=x;
}
}
}
void Identity()
{
memset(a,0,sizeof(a));
for(int i=0;i<N;++i)
{
a[i][i]=1;
}
}
#undef N //112
};
Matrix operator*(Matrix x,Matrix y)
{
Matrix ans(x.n,0);
int n=ans.n;
for(int i=1;i<=n;++i)
{
for(int j=1;j<=n;++j)
{
for(int k=1;k<=n;++k)
{
ans[i][j]+=x[i][k]*y[k][j];
ans[i][j]%=mod;
}
}
}
return ans;
}
Matrix operator^(Matrix x,int p)
{
Matrix ans(x.n,1);
ans.Identity();
while(p)
{
if (p&1) ans=ans*x;
x=x*x,p>>=1;
}
return ans;
}
int n,t,a[112][112];
void Input()
{
scanf("%lld%lld",&n,&t);
F(i,1,n) F(j,1,n)
{
scanf("%1lld",&a[i][j]);
}
}
Matrix f(91,0);
int pos(int i,int v)
{
return v*n+i;
}
void Soviet()
{
F(i,1,n)
{
F(j,1,8) f[pos(i,j)][pos(i,j-1)]=1;
F(j,1,n)
{
int x=a[i][j];
f[i][pos(j,x-1)]=1;
}
}
f=f^t;
printf("%lld\n",f[1][n]);
}
void IsMyWife()
{
Input();
Soviet();
}
#undef int //long long
}
int main()
{
Flandre_Scarlet::IsMyWife();
getchar();getchar();
return 0;
}