题解 环路

传送门

明显的矩阵优化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;
}
posted @ 2021-09-28 20:20  Administrator-09  阅读(1)  评论(0编辑  收藏  举报