跑步(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; }