跑步(walk)
题目背景:
小白非常喜欢跑步,所以他经常在校园内跑步(其实是想看美女~)。校园可以看成由N个地区,由M个道路连接。我们小白早上从一个地点出发,但是不知道怎么跑才好。小白有个习惯,不会沿着刚刚经过的道路再返回(比如从A到B经过C道路,下一次,不会再沿着C从B返回A)。
小白想知道从他出发的地点,经过Q条路,到达每个点的方案数。这样方便他去选择。
输入格式:
第一行3个整数N,M,S,Q。表示有N个地区,M条道路,从S出发,需要经过Q条路。
下面M行,每行两个整数表示A,B之间有条道路。
输出格式:
一共N行,每行一个整数表示从S到I的方案数(mod 45989)
Input
1020 9 10
1 5
5 10
10 4
10 2
10 7
4 3
10 9
2 8
5 6
6 1
2 10
4 7
9 10
9 6
7 3
7 3
7 2
1 8
9 7
4 5
Output
17420
41928
35701
40814
31937
22933
5754
15848
43620
10819
我们发现M很小
于是点代边,边带点,成功解决限制条件
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#include<cmath>
#include<cctype>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define RepD(i,n) for(int i=n;i>=0;i--)
#define MAXN (30+10)
#define MAXM (60+10)
#define F (45989)
int n,m,s,q;
int un(int i){if (i%2) return i+1;return i-1;}
struct M
{
long long a[MAXM*2][MAXM*2];
M(){For(i,120) For(j,120) a[i][j]=0;}
long long& operator()(int i,int j){return a[i][j]; }
friend M operator*(M a,M b)
{
M c;
For(i,2*m) For(j,2*m) For(k,2*m) c(i,j)=(c(i,j)+a(i,k)*b(k,j))%F;
return c;
}
void print()
{
For(i,2*m)
{
For(j,2*m) printf("%d ",a[i][j]);
puts("");
}
}
}a0,c;
int a2[MAXN],size=0;
M pow(M a,int b)
{
size=0;
while (b) {a2[++size]=b%2,b/=2;}
c=a0;
ForD(i,size-1)
{
if (a2[i]==1) c=c*c*a;
else c=c*c;
}
return c;
}
struct edge
{
int x,y;
}p[MAXM*2];
int ans[MAXN]={0};
int main()
{
freopen("walk.in","r",stdin);
freopen("walk.out","w",stdout);
scanf("%d%d%d%d",&n,&m,&s,&q);
For(i,m)
scanf("%d%d",&p[(i<<1)-1].x,&p[(i<<1)-1].y),p[i<<1].x=p[(i<<1)-1].y,p[i<<1].y=p[(i<<1)-1].x;
q--;
For(i,2*m)
For(j,2*m)
if (un(i)^j) a0(i,j)=(int)(p[i].y==p[j].x);
// a0.print();
a0=pow(a0,q);
// a0.print();
For(i,2*m)
For(j,2*m) if (p[i].x==s) ans[p[j].y]=(ans[p[j].y]+a0(i,j))%F;
For(i,n) cout<<ans[i]<<endl;
return 0;
}