「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 Ecdot dp_{i-1})

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

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

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

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

以处理(b_s ightarrow 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 ightarrow 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
",ans);
	}
}

原文地址:https://www.cnblogs.com/chasedeath/p/14429068.html