思路:矩乘优化DP
提交:3次(用了一个奇怪的东西导致常数过大)
题解:
如果可以走完正向边后又走反向边那就显然了,但是不能走,所以我们要将正反向边分别编号,区分正反向边。
所以这道题的矩阵是以边的编号(边的邻接矩阵),而非点来DP的。
具体地,记录每个边$w_i=(u_i,v_i)$和$w_{i^1}=(v_{i^1},u_{i^1})$,注意这个有向的。
设起点为$s$,终点为$t$,我们的初始矩阵$S$是一根行向量,把所有的$w_i and u_i==s $设为$1$,表示$s$与$w_i$连通;
然后转移矩阵$a$:若$v_i==u_j and i!=j xor 1$ ,即两条边相连,但不是互为正反向边,则在边的邻接矩阵中设为$1$。
然后快速幂,并令$ans=S*a$
最后求解答案时,统计所有$ans$中$w_i and v_i==t$ 的答案,即为最终的答案。
代码:
#include<cstdio> #include<iostream> #include<cstring> #define R register int using namespace std; //你弱,有什么资格休息 #define ull unsigned long long #define ll long long #define pause (for(R i=1;i<=10000000000;++i)) #define In freopen("NOIPAK++.in","r",stdin) #define Out freopen("out.out","w",stdout) namespace Fread { static char B[1<<15],*S=B,*D=B; #ifndef JACK #define getchar() (S==D&&(D=(S=B)+fread(B,1,1<<15,stdin),S==D)?EOF:*S++) #endif inline int g() { R ret=0,fix=1; register char ch; while(!isdigit(ch=getchar())) fix=ch=='-'?-1:fix; if(ch==EOF) return EOF; do ret=ret*10+(ch^48); while(isdigit(ch=getchar())); return ret*fix; } inline bool isempty(const char& ch) {return (ch<=36||ch>=127);} inline void gs(char* s) { register char ch; while(isempty(ch=getchar())); do *s++=ch; while(!isempty(ch=getchar())); } } using Fread::g; using Fread::gs; namespace Luitaryi { const int N=130,M=45989; int n,m,p,S,T,cnt=-1,x[N],y[N]; int a[N][N],s[2][N],ans[2][N],anss; inline void mul(int a[][N],int b[][N]) { R tmp[N][N]; memset(tmp,0,sizeof(tmp)); for(R i=0;i<=cnt;++i) for(R k=0;k<=cnt;++k) for(R j=0;j<=cnt;++j) (tmp[i][j]+=1ll*a[i][k]*b[k][j]%M)%=M; memcpy(a,tmp,sizeof(tmp)); } inline void qpow(int p) { R ret[N][N]; memset(ret,0,sizeof(ret)); for(R i=0;i<=cnt;++i) ret[i][i]=1; for(;p;p>>=1,mul(a,a)) if(p&1) mul(ret,a); memcpy(a,ret,sizeof(ret)); } inline void main() { n=g(),m=g(),p=g(),S=g(),T=g(); for(R i=1;i<=m;++i) { R u=g(),v=g(); x[++cnt]=u,y[cnt]=v; x[++cnt]=v,y[cnt]=u; } for(R i=0;i<=cnt;++i) for(R j=0;j<=cnt;++j) if(i!=(j^1)&&y[i]==x[j]) a[i][j]+=1; for(R i=0;i<=cnt;++i) if(x[i]==S) s[1][i]=1; qpow(p-1); for(R i=0;i<=cnt;++i) for(R j=0;j<=cnt;++j) (ans[1][j]+=1ll*s[1][i]*a[i][j]%M)%=M; for(R i=0;i<=cnt;++i) if(y[i]==T) (anss+=ans[1][i])%=M; printf("%d ",anss); } } signed main() { Luitaryi::main(); }
2019.07.20