题解 环路
明显的矩阵优化DP
考场做法是固定环的起始点,对其它部分DP
这个做法是 \(O(m^4logk)\),过不了
- 矩阵加速可不是只能加速 \(1*n\) 的矩阵,别被思维定式了
于是尝试求出从每个点到其它所有点的方案数
答案为在每个时刻从每个点到它本身的方案数的和
但这个和不好在矩阵加速的同时求出,于是考虑连续幂次和
- 关于矩阵连续幂次和的优化:一个log的写法
发现每次需要单独快速幂求的 \(A^i\) 是成倍增长的
考虑快速幂的过程,每次我们需要单独求的情况实际上就是快速幂中的if (b&1)
于是不用每次都快速幂,从上一次算的转移过来就行了
放代码:matrix calc(matrix a, int b) { if (b==1) {lst=a; return a;} matrix ans=calc(a, b>>1); ans=ans+ans*lst; lst=lst*lst; if (b&1) lst=lst*a, ans=ans+lst; return ans; }
于是这个题就做完了
Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 105
#define reg register int
#define ll long long
//#define int long long
int n, m;
ll mod;
char s[N];
bool mp[N][N];
inline void md(ll& a, ll b) {a+=b; a=a>=mod?a-mod:a;}
inline ll md(ll a) {return a>=mod?a-mod:a;}
namespace force{
ll dp[1010][N][N];
void solve() {
for (int i=1; i<=n; ++i) dp[0][i][i]=1;
for (int k=1; k<m; ++k)
for (int i=1; i<=n; ++i)
for (int j=1; j<=n; ++j)
for (int v=1; v<=n; ++v) if (mp[i][v])
md(dp[k][j][i], dp[k-1][j][v]);
ll ans=0;
for (int k=1; k<m; ++k)
for (int i=1; i<=n; ++i)
md(ans, dp[k][i][i]);
printf("%lld\n", ans);
exit(0);
}
}
namespace task1{
ll dp[1010][N], ans;
void solve() {
for (int j=1; j<=n; ++j) {
memset(dp, 0, sizeof(dp));
dp[0][j]=1;
for (int k=1; k<m; ++k)
for (int i=1; i<=n; ++i)
for (int v=1; v<=n; ++v) if (mp[i][v])
md(dp[k][i], dp[k-1][v]);
for (int k=1; k<m; ++k) md(ans, dp[k][j]);
}
printf("%lld\n", ans);
exit(0);
}
}
namespace task2{
struct matrix{
int n, m;
ll a[N][N];
matrix(){memset(a, 0, sizeof(a));}
matrix(int x, int y):n(x),m(y){memset(a, 0, sizeof(a));}
inline void resize(int x, int y){n=x; m=y; memset(a, 0, sizeof(a));}
inline void put() {for (int i=1; i<=n; ++i) {for (int j=1; j<=m; ++j) cout<<a[i][j]<<' '; cout<<endl;}}
inline ll* operator [] (int t) {return a[t];}
inline matrix operator * (matrix b) {
matrix ans(n, b.m);
for (reg i=1; i<=n; ++i)
for (reg k=1; k<=m; ++k) if (a[i][k])
for (reg j=1; j<=b.m; ++j) if (b[k][j])
ans[i][j]=md(ans[i][j]+a[i][k]*b[k][j]%mod);
return ans;
}
}mat, t;
matrix qpow(matrix a, int b) {
matrix ans=a; --b;
while (b) {
if (b&1) ans=ans*a;
a=a*a; b>>=1;
}
return ans;
}
void solve() {
ll ans=0;
for (reg j=1; j<=n; ++j) {
// cout<<"j: "<<j<<endl;
mat.resize(1, n+1); t.resize(n+1, n+1);
mat[1][j]=1; t[j][n+1]=1; t[n+1][n+1]=1;
for (reg i=1; i<=n; ++i)
for (reg k=1; k<=n; ++k)
if (mp[i][k]) t[k][i]=1;
// cout<<"---t---"<<endl; t.put(); cout<<endl;
t=qpow(t, m);
mat=mat*t;
ans=(ans+mat[1][n+1]-1)%mod;
}
printf("%lld\n", (ans%mod+mod)%mod);
exit(0);
}
}
namespace task{
struct matrix{
int n, m;
ll a[N][N];
matrix(){memset(a, 0, sizeof(a));}
matrix(int x, int y):n(x),m(y){memset(a, 0, sizeof(a));}
inline void resize(int x, int y){n=x; m=y; memset(a, 0, sizeof(a));}
inline void put() {for (int i=1; i<=n; ++i) {for (int j=1; j<=m; ++j) cout<<a[i][j]<<' '; cout<<endl;}}
inline ll* operator [] (int t) {return a[t];}
inline matrix operator * (matrix b) {
matrix ans(n, b.m);
for (reg i=1; i<=n; ++i)
for (reg k=1; k<=m; ++k) if (a[i][k])
for (reg j=1; j<=b.m; ++j) if (b[k][j])
ans[i][j]=md(ans[i][j]+a[i][k]*b[k][j]%mod);
return ans;
}
inline matrix operator + (matrix b) {
matrix ans(n, m);
for (int i=1; i<=n; ++i)
for (int j=1; j<=m; ++j)
ans[i][j]=(ans[i][j]+a[i][j]+b[i][j])%mod;
return ans;
}
}mat, lst;
matrix qpow(matrix a, int b) {
matrix ans=a; --b;
while (b) {
if (b&1) ans=ans*a;
a=a*a; b>>=1;
}
return ans;
}
#if 1
matrix calc(matrix a, int b) {
if (b==1) {lst=a; return a;}
matrix ans=calc(a, b>>1);
ans=ans*lst+ans;
lst=lst*lst;
if (b&1) lst=lst*a, ans=ans+lst;
return ans;
}
#else
matrix calc(matrix a, int b) {
if (b==1) return a;
matrix tem=calc(a, b>>1);
tem=tem*qpow(a, b>>1)+tem;
if (b&1) tem=tem+qpow(a, b);
return tem;
}
#endif
void solve() {
ll ans=0;
// cout<<"j: "<<j<<endl;
mat.resize(n, n);
for (int i=1; i<=n; ++i)
for (int j=1; j<=n; ++j)
if (mp[i][j]) mat[i][j]=1;
// cout<<"---t---"<<endl; t.put(); cout<<endl;
// t=qpow(t, m-1);
// mat=mat*t;
mat=calc(mat, m-1);
// cout<<"---mat---"<<endl;
// mat.put(); cout<<endl;
for (int i=1; i<=n; ++i) ans=(ans+mat[i][i])%mod;
printf("%lld\n", (ans%mod+mod)%mod);
exit(0);
}
}
signed main()
{
freopen("tour.in", "r", stdin);
freopen("tour.out", "w", stdout);
scanf("%d", &n);
for (int i=1; i<=n; ++i) {
scanf("%s", s+1);
for (int j=1; j<=n; ++j) mp[i][j]=(s[j]=='Y')?1:0;
}
scanf("%d%lld", &m, &mod);
// force::solve();
// task1::solve();
task::solve();
return 0;
}