P5789 [TJOI2017]可乐 矩阵乘法
P5789 [TJOI2017]可乐 矩阵乘法
题目链接
说实话这个自爆的问题难住我了, 其他的都还挺好想的.
操作一 : 走到相邻的点, 如果\(x\)可以走到\(y\), 那么我们另\(g[x][y] = g[y][x] = 1\), 表示这两个点之间可以相互走.
操作二 : 停在原地 , 相当于自己有一条到自己的边.
操作三 : 自爆 , 我们可以假设有一个0点, 然后所有点都可以向0点连边, 而0点不能向外连边. 这个和自爆的性质是一样的.
其实也蛮水的, TESknight零秒就切出来了%%%
#include <bits/stdc++.h>
using namespace std;
inline long long read() {
long long s = 0, f = 1; char ch;
while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
return s * f;
}
const int N = 105, mod = 2017;
int n, m, k, ans_;
struct mat {
int v[N][N];
void init() { for(int i = 0;i <= n; i++) for(int j = 0;j <= n; j++) v[i][j] = 0; }
friend mat operator * (const mat &a, const mat &b) {
mat c; c.init();
for(int k = 0;k <= n; k++)
for(int i = 0;i <= n; i++)
if(a.v[i][k])
for(int j = 0;j <= n; j++)
if(b.v[k][j]) c.v[i][j] = (c.v[i][j] + 1ll * a.v[i][k] * b.v[k][j] % mod) % mod;
return c;
}
} ans, turn;
mat ksm(mat x, int y) {
mat res; res.init(); for(int i = 0;i <= n; i++) res.v[i][i] = 1;
while(y) { if(y & 1) res = res * x; x = x * x; y >>= 1; }
return res;
}
int main() {
n = read(); m = read();
for(int i = 1, x, y;i <= m; i++) x = read(), y = read(), turn.v[x][y] = turn.v[y][x] = 1;
for(int i = 0;i <= n; i++) turn.v[i][0] = turn.v[i][i] = 1;
k = read(); ans = ksm(turn, k);
for(int i = 0;i <= n; i++) ans_ = (ans_ + ans.v[1][i]) % mod;
printf("%d", ans_);
return 0;
}