「USACO 2020.12 Platinum」Spaceship

「USACO 2020.12 Platinum」Spaceship

看到题目第一个想到的是:按照路径长度可以确定按钮次数和路径次数

然而路径长度是\(2^k\)级别的。。

下文认为\(n,q,k\)同阶

既然无法考虑长度,那么就直接在\(dp\)时将路径作为状态压入

\(dp_{i,s,t}\)表示前面\(i\)个按钮未按过,从\(s\)走到\(t\)的路径数

显然\(dp_{i}\)可以看做一个类似矩阵的转移,设邻接矩阵为\(E\)

那么得到\(dp_{i}=dp_{i-1}+dp_{i-1}\cdot E\cdot dp_{i-1}\)

(\(dp_i\)不一定按了\(i\)这个按钮,所以考虑按或者不按)

那么对于\(b_s,b_t\)的情况,考虑把操作序列分成两段

显然操作序列有唯一一个按过恰好一次的最大的按钮\(max\),可以在这里将操作序列分成两段

处理出\(b_s\)\(max\)\(max\)\(b_t\)的两部分方案数合并即可

以处理\(b_s\rightarrow max\)为例

类似上面的操作,令\(F_{i,j}\)表示最大按钮为\(i\),且按过\(i\)之后没有按过其他按钮,停留在\(j\)的方案数 (\(F_i\)是一个向量)

初始显然有\(F_{b_s,s}=1\)

\(\displaystyle i>b_s,F_{i}=\sum_{j<i} F_{j}\cdot dp_{j-1}\cdot E\)(按过\(j\)之后可以继续按\([1,j-1]\))

前缀和即可,复杂度为\(O(n^3)\)

同理处理出\(max\rightarrow b_t\)的权值合并即可

#include<bits/stdc++.h>
using namespace std;
#define Mod1(x) ((x>=P)&&(x-=P))
#define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(int i=a,i##end=b;i>=i##end;--i)

const int N=62,P=1e9+7,INF=1e9+10;

int n,m,q;
struct Mat{
	int a[N][N];
	void clear(){ memset(a,0,sizeof a); }
	Mat operator * (const Mat &x) const {
		Mat res; res.clear();
		rep(i,1,n) rep(j,1,n) if(a[i][j]) rep(k,1,n) res.a[i][k]=(res.a[i][k]+1ll*a[i][j]*x.a[j][k])%P;
		return res;
	}
	Mat operator + (const Mat &x) const {
		Mat res;
		rep(i,1,n) rep(j,1,n) res.a[i][j]=a[i][j]+x.a[i][j],Mod1(res.a[i][j]);
		return res;
	}
} I,E,dp[N];
int F[N][N],G[N][N];
int S[N][N];

int main(){
	freopen("spaceship.in","r",stdin),freopen("spaceship.out","w",stdout);
	scanf("%d%d%d",&n,&m,&q);
	rep(i,1,n) I.a[i][i]=1;
	rep(i,1,n) rep(j,1,n) scanf("%1d",&E.a[i][j]);
	dp[0]=I;
	rep(i,1,m) dp[i]=dp[i-1]+dp[i-1]*E*dp[i-1];
	while(q--) {
		int bs,s,bt,t; scanf("%d%d%d%d",&bs,&s,&bt,&t);
		memset(F,0,sizeof F),memset(G,0,sizeof G);
		memset(S,0,sizeof S);
		F[bs][s]=1;
		rep(i,1,n) S[bs][i]=dp[bs-1].a[s][i];
		rep(i,bs+1,m) {
			rep(a,1,n) if(S[i-1][a]) rep(b,1,n) F[i][b]=(F[i][b]+1ll*S[i-1][a]*E.a[a][b])%P;
			rep(a,1,n) S[i][a]=S[i-1][a];
			rep(a,1,n) if(F[i][a]) rep(b,1,n) S[i][b]=(S[i][b]+1ll*F[i][a]*dp[i-1].a[a][b])%P;
		}

		memset(S,0,sizeof S);
		G[bt][t]=1;
		rep(i,1,n) S[bt][i]=dp[bt-1].a[i][t];
		rep(i,bt+1,m) {
			rep(a,1,n) rep(b,1,n) G[i][a]=(G[i][a]+1ll*S[i-1][b]*E.a[a][b])%P;
			rep(a,1,n) S[i][a]=S[i-1][a];
			rep(a,1,n) rep(b,1,n) S[i][a]=(S[i][a]+1ll*G[i][b]*dp[i-1].a[a][b])%P;
		}

		int ans=0;
		rep(i,1,m) rep(j,1,n) ans=(ans+1ll*F[i][j]*G[i][j])%P;
		printf("%d\n",ans);
	}
}

posted @ 2021-02-22 11:11  chasedeath  阅读(137)  评论(0编辑  收藏  举报