WOJ26 矩阵快速幂:给定一个
注意:如果在时刻
3. 解题思路
题意是求在
可以这么考虑,求经过
那么,问题就很简单的转化为熟悉的矩阵快速幂了,经过
问题现在转化为对矩阵幂求和了,即求矩阵
设
下面是求
分治法: 利用Sx=Sx2+Sx2?Ax2 ,进行分治即可。复杂度:O(N3log2(T)) 构造矩阵法:根据Sx=A0+Sx?1?A 很容易构造出矩阵转移式:[SxE]=[AOEE]?[Sx?1E] E 是单位矩阵,O 是零矩阵。这样搞的复杂度是O((2N)3log(T)) 通项公式法?: 这个做法是我yy的。理论上应该是可行的。类比等比数列求和。Sx=E?AxE?A 。这样就需要求一个矩阵的逆(高斯消元来做,好麻烦)。
最后这个题目矩阵挺大的。递归一多肯定爆栈,所以可以必须用全局变量或静态变量。推荐用静态变量,返回引用值来做,简单易实现,效率还高。
4. 实现代码
/** 法一:构造矩阵法 **/
#include
using namespace std;
typedef long long LL;
typedef long double LB;
typedef pair PII;
typedef pair PLL;
typedef vector VI;
const int INF = 0x3f3f3f3f;
const LL INFL = 0x3f3f3f3f3f3f3f3fLL;
const double eps = 1e-8;
const double PI = acos(-1.0);
const int MAXN = 100000 + 5;
const int MX = 100 + 1;
const int MOD = 1e9 + 7;
int n, m, t, msz;
struct Mat {
LL d[MX << 1][MX << 1];
void I() { memset(d, 0, sizeof(d)); }
void E() { I(); for(int i = 1; i <= msz; i++) d[i][i] = 1; }
Mat& operator * (const Mat& e) const {
static Mat ret; ret.I();
for(int k = 1; k <= msz; k++) {
for(int i = 1; i <= msz; i++) {
if(d[i][k] == 0) continue;
for(int j = 1; j <= msz; j++) {
ret.d[i][j] += d[i][k] * e.d[k][j];
ret.d[i][j] %= MOD;
}
}
}
return ret;
}
Mat& operator ^ (int b) const {
static Mat x(*this), ret; ret.E();
while(b > 0) {
if(b & 1) ret = ret * x;
x = x * x;
b >>= 1;
}
return ret;
}
void P() const {
for(int i = 1; i <= msz; i++) {
for(int j = 1; j <= msz; j++) {
printf("%lld ", d[i][j]);
}
puts("");
}
}
} init, tran, ans;
int G[MX];
int main() {
#ifdef ___LOCAL_WONZY___
freopen("input.txt", "r", stdin);
#endif // ___LOCAL_WONZY___
static int u, v;
scanf("%d %d", &n, &m);
memset(G, 0, sizeof(G));
init.I(); tran.I();
msz = ((n - 1) << 1);
for(int i = 1; i <= n - 1; ++i) {
init.d[i][i] = 1;
tran.d[i][i + n - 1] = 1;
}
for(int i = n; i <= msz; ++i) {
init.d[i][i - n + 1] = 1;
tran.d[i][i] = 1;
}
for(int i = 1; i <= m; ++i) {
scanf("%d %d", &u, &v);
if(u > v) swap(u, v);
if(v == n) { G[u] = 1; continue; }
tran.d[u][v] = ++ tran.d[v][u];
}
scanf("%d", &t);
tran = (tran ^ (t - 1));
ans = tran * init;
LL rs = 0;
for(int i = 1; i <= (n - 1); ++i) {
if(!G[i]) continue;
rs = (rs + ans.d[1][i] * G[i]) % MOD;
}
printf("%lld\n", rs);
#ifdef ___LOCAL_WONZY___
cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << " ms." << endl;
#endif // ___LOCAL_WONZY___
return 0;
}
/** 法二:分治法 **/
#include
using namespace std;
typedef long long LL;
typedef long double LB;
typedef pair PII;
typedef pair PLL;
typedef vector VI;
const int INF = 0x3f3f3f3f;
const LL INFL = 0x3f3f3f3f3f3f3f3fLL;
const double eps = 1e-8;
const double PI = acos(-1.0);
const int MAXN = 100000 + 5;
const int MX = 100 + 1;
const int MOD = 1e9 + 7;
int n, m, t;
struct Mat {
LL d[MX][MX];
void I() { memset(d, 0, sizeof(d)); }
void E() { I(); for(int i = 1; i <= n - 1; i++) d[i][i] = 1; }
Mat& operator * (const Mat& e) const {
static Mat ret; ret.I();
for(int k = 1; k <= n - 1; k++) {
for(int i = 1; i <= n - 1; i++) {
if(d[i][k] == 0) continue;
for(int j = 1; j <= n - 1; j++) {
ret.d[i][j] += d[i][k] * e.d[k][j];
ret.d[i][j] %= MOD;
}
}
}
return ret;
}
Mat& operator ^ (int b) const {
static Mat x, ret; x = (*this), ret.E();
while(b > 0) {
if(b & 1) ret = ret * x;
x = x * x;
b >>= 1;
}
return ret;
}
Mat& operator + (const Mat& e) const {
static Mat ret;
for(int i = 1; i <= n - 1; i++) {
for(int j = 1; j <= n - 1; j++) {
ret.d[i][j] = (d[i][j] + e.d[i][j]) % MOD;
}
}
return ret;
}
void P() const {
for(int i = 1; i <= n - 1; i++) {
for(int j = 1; j <= n - 1; j++) {
printf("%lld ", d[i][j]);
}
puts("");
}
}
} init, tran, ans;
int G[MX];
Mat& ask(const Mat& a, int b) {
static Mat ret;
if(b <= 1) { ret.E(); return ret; }
int md = (b >> 1);
ret = ask(a, md);
ret = ret + ret * (a ^ md);
if(b & 1) ret = ret + (a ^ (b - 1));
return ret;
}
int main() {
#ifdef ___LOCAL_WONZY___
freopen("input.txt", "r", stdin);
#endif // ___LOCAL_WONZY___
static int u, v;
scanf("%d %d", &n, &m);
memset(G, 0, sizeof(G));
tran.I();
for(int i = 1; i <= m; ++i) {
scanf("%d %d", &u, &v);
if(u > v) swap(u, v);
if(v == n) { G[u] = 1; continue; }
tran.d[u][v] = ++ tran.d[v][u];
}
scanf("%d", &t);
ans = ask(tran, t);
LL rs = 0;
for(int i = 1; i <= (n - 1); ++i) {
if(!G[i]) continue;
rs = (rs + ans.d[1][i] * G[i]) % MOD;
}
printf("%lld\n", rs);
#ifdef ___LOCAL_WONZY___
cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << " ms." << endl;
#endif // ___LOCAL_WONZY___
return 0;
}