沼泽鳄鱼
肥宅快乐水(滑稽
这两道题其实差不多
肥宅快乐水简单一些,先说他
题目大意就是给你一张图,每个时间段你有几个抉择:
1.停留
2.走一步
3.自爆(emmmmm)
问经过k个时间的方案数,n特别的小,k特别的大
通过这道题,我们引入一个东西,叫做邻接矩阵乘法
就是一个图,走k步的方案数,等于他的邻接矩阵的n次方!
为什么呢?
比如说我们设这个邻接矩阵是
G
G
G
那么
G
2
[
i
]
[
j
]
=
∑
k
=
1
n
G
[
i
]
[
k
]
∗
G
[
k
]
[
j
]
G^2[i][j]=\sum_{k=1}^n G[i][k]*G[k][j]
G2[i][j]=k=1∑nG[i][k]∗G[k][j]
通过乘法原理和加法原理,我们知道,这就是
i
i
i到
j
j
j走两步的方案数(也可以想象成
f
l
o
y
d
floyd
floyd)
G
3
[
i
]
[
j
]
=
∑
k
=
1
n
∑
l
=
1
n
G
[
i
]
[
k
]
∗
G
[
k
]
[
l
]
∗
G
[
l
]
[
j
]
G^3[i][j]=\sum_{k=1}^n\sum_{l=1}^n G[i][k]*G[k][l]*G[l][j]
G3[i][j]=k=1∑nl=1∑nG[i][k]∗G[k][l]∗G[l][j]
本质上还是
i
i
i到
j
j
j走三次的方案数
我们就可以把它推到任意正整数次幂QAQ
知道了这个这道题就很好做了
先处理好初始邻接矩阵
对于停留,自己给自己连一条边
对于走一步,正常邻接矩阵
对于自爆问题,我们只需要把所有的点都连向一个节点
n
+
1
n+1
n+1并且不给他连出边就可以了
那么答案就是 ∑ i = 1 n + 1 G k [ 1 ] [ i ] \sum_{i=1}^{n+1}G^k[1][i] ∑i=1n+1Gk[1][i]
代码:
# include <cstdio>
# include <algorithm>
# include <cstring>
# include <cmath>
# include <climits>
# include <iostream>
# include <string>
# include <queue>
# include <stack>
# include <vector>
# include <set>
# include <map>
# include <cstdlib>
# include <ctime>
using namespace std;
# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)
typedef long long ll;
const int N=35;
const int mod=2017;
const double eps=1e-7;
template <typename T> void read(T &x){
x=0;int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
x*=f;
}
int n,m,t;
struct matrix{
int x;
int a[N][N];
matrix(){x=0,memset(a,0,sizeof(a));}
matrix operator * (const matrix &y)const{
matrix res;
res.x=x;
Rep(i,1,x)
Rep(j,1,x)
Rep(k,1,x)
res.a[i][j]=(res.a[i][j]+a[i][k]*y.a[k][j])%mod;
return res;
}
void build(int sz){
x=sz;
Rep(i,1,x)a[i][i]=1;
}
void print(){
Rep(i,1,x)
Rep(j,1,x)
printf("%d%c",a[i][j],j==x?'\n':' ');
}
}a;
int ans;
matrix Qpow(matrix base,int ind){
matrix res;
res.build(n+1);
// res.print();
while(ind){
if(ind&1)res=res*base;
base=base*base;
ind>>=1;
}
return res;
}
int main()
{
read(n),read(m);
a.build(n+1);
Rep(i,1,m){
int x,y;
read(x),read(y);
a.a[x][y]=a.a[y][x]=1;
}
Rep(i,1,n)a.a[i][n+1]=1;
read(t);
a=Qpow(a,t);
// a.print();
Rep(j,1,n+1)
ans=(ans+a.a[1][j]+mod)%mod;
printf("%d\n",ans);
return 0;
}
沼泽鳄鱼那道题其实和可乐差不多,唯一有区别的地方时在有些时候有些地方不能走
这个怎么处理呢?
我们观察发现,那些食人鱼的游动的周期是2,3,4,他们的lcm是12,这样我们可以构建12个状态,然后再做矩阵乘法就可以了
# include <cstdio>
# include <algorithm>
# include <cstring>
# include <cmath>
# include <climits>
# include <iostream>
# include <string>
# include <queue>
# include <stack>
# include <vector>
# include <set>
# include <map>
# include <cstdlib>
# include <ctime>
using namespace std;
# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)
typedef long long ll;
const int N=105;
const int inf=0x7fffffff;
const int mod=10000;
template <typename T> void read(T &x){
x=0;int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
x*=f;
}
int n,m,K,nf;//let you down
int s,t;
bool cyl[N][15];
bool beg[N][N];
struct matrix{
int a[N][N];
int x,y;
matrix(){memset(a,0,sizeof(a));}
matrix operator * (const matrix &xx) const{
matrix res;
res.x=x,res.y=xx.y;
Rep(i,1,x)
Rep(j,1,xx.y)
Rep(k,1,y)
res.a[i][j]=(res.a[i][j]+a[i][k]*xx.a[k][j])%mod;
return res;
}
void build(int sz){
x=sz,y=sz;
Rep(i,1,x)
a[i][i]=1;
}
void print(){
Rep(i,1,x){
Rep(j,1,y)
printf("%d ",a[i][j]);
puts("");
}
}
}ans,a[N],prod;
matrix Qpow(matrix base,int ind){
matrix res;
res.build(n);
while(ind){
if(ind&1)res=res*base;
base=base*base;
ind>>=1;
}
return res;
}
int main()
{
read(n),read(m),read(s),read(t),read(K);
Rep(i,1,m){
int x,y;
read(x),read(y);
x++,y++;
beg[x][y]=beg[y][x]=true;
}
read(nf);
Rep(i,1,nf){
int trn,x;
read(trn);
Rep(j,0,trn-1){
read(x);
x++;
for(int k=j;k<12;k+=trn)
cyl[x][k]=true;
}
}
Rep(which,0,11)
Rep(i,1,n)
Rep(j,1,n)
if(beg[i][j]&&!cyl[j][which])
a[which].a[i][j]=1;
Rep(i,0,11)a[i].x=a[i].y=n;
prod.build(n);
int times=K/12,add=K%12;
Rep(i,1,11)prod=prod*a[i];
prod=prod*a[0];
ans=Qpow(prod,times);
Rep(i,1,add)ans=ans*a[i];
printf("%d\n",ans.a[s+1][t+1]);
return 0;
}