[USACO20DEC] Spaceship P 题解

solution:

\(dp_{a,f_1,b,f_2,c}\)表示从a到b,使用最大的按钮编号$\leq $c。

  • \(f_1\)表示是否对第一个按的有要求,如果有,则\(a=s\)需要先按下\(b_s\)
  • \(f_2\)表示是否对最后一个有要求,如果有,则\(b=t\),最后要按下\(b_t\)

先考虑简单的情况:\(f_{1}=f_{2}=0\),以下用\(dp_{a,b,c}\)代替\(dp_{a,0,b,0,c,0}\)

有两种转移:

  • 按的最大的<c,则\(dp_{a,b,c}+=dp_{a,b,c-1}\)

  • 按的最大的=c, 则\(dp_{a,b,c}+=\sum _{r}(\sum _{i,e[i,r]=1} dp_{a,i,c-1})*(\sum _{j,e[r,j]=1}dp_{j,b,c-1})\),显然这两个部分都是可以\(O(N^4)\)预处理的。设\(g_{a,r,c}=\sum_{e[b,r]=1} dp_{a,b,c},f_{r,a,c}=\sum _{e[r,b]=1} dp_{b,a,c}\)。则\(dp_{a,b,c}+=\sum _{r} g_{a,r,c-1}\times f_{r,b,c-1}\)

这部分的转移是\(O(N^4)\)的。

可以发现\(f_1=f_2=0\)的部分对于所有的询问都是互不影响的。所以我们可以先\(O(N^4)\)的算出这些答案。

然后我们再考虑\(f_1=1\)的情况,可以发现有用的状态的a一定等于s。同理\(f_2=1\)的时候,有用状态的b等于t。

所以对于每一个询问,有用状态是\(O(N^2K)\)级别的。

总时间复杂度为\(O(N^3*K+N^2*Q*K)\)

/*
{
######################
#       Author       #
#        Gary        #
#        2020        #
######################
*/
#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define LL long long
#define IT iterator
#define PB push_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define POB pop_back
#define ff fflush(stdout)
#define fastio ios::sync_with_stdio(false)
#define check_min(a,b) a=min(a,b)
#define check_max(a,b) a=max(a,b)
using namespace std;
//inline int read(){
//    int x=0;
//    char ch=getchar();
//    while(ch<'0'||ch>'9'){
//        ch=getchar();
//    }
//    while(ch>='0'&&ch<='9'){
//        x=(x<<1)+(x<<3)+(ch^48);
//        ch=getchar();
//    }
//    return x;
//}
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
/*}
*/
int n,k,q;
const int MAXN=60+1; 
int dp[2][2][MAXN][MAXN][MAXN],g[2][MAXN][MAXN][MAXN],f[2][MAXN][MAXN][MAXN];
bool e[MAXN][MAXN];
const int MOD=1e9+7;
void add(int& x,int y){
	x+=y;
	if(x>=MOD) x-=MOD;
}
void normal(){
	rb(c,1,k){
		rb(r,1,n){
			rb(a,1,n)rb(b,1,n){
				if(e[b][r]){
					add(g[0][r][a][c],dp[0][0][a][b][c-1]);
				}		
				if(e[r][a]){
					add(f[0][r][b][c],dp[0][0][a][b][c-1]);
				}
			}
			add(f[0][r][r][c],1);
			add(g[0][r][r][c],1);
		}
		rb(i,1,n) rb(j,1,n){
			dp[0][0][i][j][c]=dp[0][0][i][j][c-1];
			rb(r,1,n) add(dp[0][0][i][j][c],1ll*g[0][r][i][c]*f[0][r][j][c]%MOD);
		}
	}
}
int bs,s,bt,t;
int calc(){
	rep(i,2) rep(j,2) if(i+j) memset(dp[i][j],0,sizeof(dp[i][j]));
	memset(g[1],0,sizeof(g[1]));
	memset(f[1],0,sizeof(f[1]));
	rb(c,1,k){
		rb(r,1,n){
			rb(i,1,n){
				if(e[i][r]){
					add(g[1][r][s][c],dp[1][0][s][i][c-1]);
				}
				if(e[r][i]){
					add(f[1][r][t][c],dp[0][1][i][t][c-1]);
				}
			}
		}
		if(c==bs){
			add(g[1][s][s][c],1);
		}
		if(c==bt){
			add(f[1][t][t][c],1);	
		}
		add(dp[1][1][s][t][c],dp[1][1][s][t][c-1]);
		rb(i,1,n){
			add(dp[1][0][s][i][c],dp[1][0][s][i][c-1]);
			add(dp[0][1][i][t][c],dp[0][1][i][t][c-1]);
			rb(r,1,n){
				add(dp[1][0][s][i][c],1ll*g[1][r][s][c]*f[0][r][i][c]%MOD);
				add(dp[0][1][i][t][c],1ll*g[0][r][i][c]*f[1][r][t][c]%MOD);
			}
		}
		rb(r,1,n)
			add(dp[1][1][s][t][c],1ll*g[1][r][s][c]*f[1][r][t][c]%MOD);
	}
	return dp[1][1][s][t][k];
}
int main(){
	scanf("%d%d%d",&n,&k,&q);
	rb(i,1,n) rb(j,1,n){
		char c;
		cin>>c;
		e[i][j]=c-'0';
	}
	normal(); 
	rb(T,1,q){
		scanf("%d%d%d%d",&bs,&s,&bt,&t);
		printf("%d\n",calc());
	}		
	return 0;
}
/*
6 20 5
110101
011001
001111
101111
111010
000001
2 5 2 5
6 1 5 2
3 4 8 3
9 3 3 5
5 1 3 4
*/
posted @ 2020-12-25 16:37  WWW~~~  阅读(161)  评论(0)    收藏  举报