您的位置:首页 > 其它

[BZOJ]1875: [SDOI2009]HH去散步 矩阵乘法优化DP

2017-12-26 09:59 465 查看
Description

HH有个一成不变的习惯,喜欢饭后百步走。所谓百步走,就是散步,就是在一定的时间 内,走过一定的距离。 但是同时HH又是个喜欢变化的人,所以他不会立刻沿着刚刚走来的路走回。 又因为HH是个喜欢变化的人,所以他每天走过的路径都不完全一样,他想知道他究竟有多 少种散步的方法。 现在给你学校的地图(假设每条路的长度都是一样的都是1),问长度为t,从给定地 点A走到给定地点B共有多少条符合条件的路径

题解:

如果状态为到某个点的方案数,则不好解决走回头路的问题,所以设计状态为到某条边的方案数,这个问题就迎刃而解了。但是t很大,所以要矩阵乘法优化,若i能够转移到j,那么矩阵的(i,j)位置+1,就构造出矩阵了。

代码:

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Mod=45989;
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
struct Edge{int x,y,next;}e[124];
int len=-1,last[22];
void ins(int x,int y){int t=++len;
4000
e[t].x=x;e[t].y=y;e[t].next=last[x];last[x]=t;}
int N,M,t,A,B;
struct Matrix{int a[124][124];}m,b,one;
Matrix operator * (Matrix x,Matrix y)
{
Matrix ans;memset(ans.a,0,sizeof(ans.a));
for(int i=0;i<=M*2;i++)
for(int j=0;j<=M*2;j++)
for(int k=0;k<=M*2;k++)
ans.a[i][j]=(ans.a[i][j]+x.a[k][j]*y.a[i][k])%Mod;
return ans;
}
Matrix Pow(Matrix x,int y)
{
if(y==0)return one;
if(y==1)return x;
Matrix t=Pow(x,y>>1),ans=t*t;
if(y&1)ans=ans*x;
return ans;
}
int main()
{
memset(last,-1,sizeof(last));
memset(m.a,0,sizeof(m.a));
memset(b.a,0,sizeof(b.a));
memset(one.a,0,sizeof(one.a));
for(int i=1;i<=120;i++)one.a[i][i]=1;
N=read(),M=read(),t=read(),A=read(),B=read();
for(int i=1;i<=M;i++)
{
int x=read(),y=read();
ins(x,y);ins(y,x);
}
for(int i=0;i<=len;i++)
{
for(int j=0;j<=len;j++)
{
if(i==(j^1))continue;
if(e[j].y==e[i].x)m.a[i][j]++;
}
}
m=Pow(m,t-1);
for(int i=last[A];i!=-1;i=e[i].next)b.a[i][0]=1;
b=b*m;
int ans=0;
for(int i=0;i<=len;i++)
if(e[i].y==B)ans=(ans+b.a[i][0])%Mod;
printf("%d",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: