专栏文章

P7155 题解

P7155题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@minhm5ig
此快照首次捕获于
2025/12/02 02:33
3 个月前
此快照最后确认于
2025/12/02 02:33
3 个月前
查看原文
考虑按按钮的序列,对其建笛卡尔树,尝试对该结构设计 dp。
预处理,考虑 dpi,j,kdp_{i,j,k} 表示按下 ii 按钮对应子树,从 jj 走到 kk 的方案数。转移的时候先求前缀和,再分布转移(求出往右一步和往左一步的答案再合并)。总复杂度 O(n4)O(n^4)
对于查询,考虑也类似做。区别在于我们需要区分在按的编号最大的按钮前/后,且不需要记录某一个端点(显然,有一个端点在最大位置前后分别为 s,ts,t),因此可以 O(n3)O(n^3) 解决。最后枚举最大值合并即可。注意特判最大值是两端/不走动的情况。
总复杂度 O(n4+qn3)O(n^4+qn^3)
CPP
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int mod=1e9+7;
inline void add(int &i,int j){
	i+=j;
	if(i>=mod) i-=mod;
}
inline int addv(int i,int j){
	i+=j;
	if(i>=mod) i-=mod;
	return i;
}
int qp(int a,int b){
	int ans=1;
	while(b){
		if(b&1) (ans*=a)%=mod;
		(a*=a)%=mod;
		b>>=1;
	}
	return ans;
}
int n,k,q;
bool g[65][65];
int f[65][65][65];
int fl[65][65][65],fr[65][65][65];
int dp1[65][65],dp2[65][65];
int dp1r[65][65],dp2l[65][65];
signed main(){
	cin>>n>>k>>q;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			char c; cin>>c;
			g[i][j]=c-'0'; 
		} 
	}
	for(int i=1;i<=k;i++){
		for(int x=1;x<=n;x++) for(int y=1;y<=n;y++) f[i][x][y]=f[i-1][x][y];
		for(int x=1;x<=n;x++) for(int y=1;y<=n;y++) for(int z=1;z<=n;z++) if(g[y][z]) add(fr[i-1][x][z],f[i-1][x][y]);
		for(int x=1;x<=n;x++) for(int y=1;y<=n;y++) for(int z=1;z<=n;z++) if(g[x][y]) add(fl[i-1][x][z],f[i-1][y][z]);
		for(int x=1;x<=n;x++) for(int y=1;y<=n;y++) for(int z=1;z<=n;z++) add(f[i][x][z],fr[i-1][x][y]*fl[i-1][y][z]%mod);
		for(int x=1;x<=n;x++) for(int y=1;y<=n;y++) add(f[i][x][y],fr[i-1][x][y]);
		for(int x=1;x<=n;x++) for(int y=1;y<=n;y++) add(f[i][x][y],fl[i-1][x][y]);
		for(int x=1;x<=n;x++) add(f[i][x][x],1);
	}
	while(q--){
		int bs,s,bt,t; cin>>bs>>s>>bt>>t;
		memset(dp1,0,sizeof(dp1));
		memset(dp1r,0,sizeof(dp1r));
		memset(dp2,0,sizeof(dp2));
		memset(dp2l,0,sizeof(dp2l));
		{
			for(int x=1;x<=n;x++) add(dp1[bs][x],fl[bs-1][s][x]);
			add(dp1[bs][s],1);
			for(int i=bs+1;i<=k;i++){
				for(int x=1;x<=n;x++) dp1[i][x]=dp1[i-1][x];
				for(int x=1;x<=n;x++) for(int y=1;y<=n;y++) if(g[x][y]) add(dp1r[i-1][y],dp1[i-1][x]);
				for(int x=1;x<=n;x++) for(int y=1;y<=n;y++) add(dp1[i][y],dp1r[i-1][x]*fl[i-1][x][y]%mod);
				for(int x=1;x<=n;x++) add(dp1[i][x],dp1r[i-1][x]);
			}
//			cout<<dp1[1][1]<<" "<<dp1[2][2]<<" "<<dp1[3][3]<<"\n";
		}
		{
			for(int x=1;x<=n;x++) add(dp2[bt][x],fr[bt-1][x][t]);
			add(dp2[bt][t],1);
			for(int i=bt+1;i<=k;i++){
				for(int x=1;x<=n;x++) dp2[i][x]=dp2[i-1][x];
				for(int x=1;x<=n;x++) for(int y=1;y<=n;y++) if(g[x][y]) add(dp2l[i-1][x],dp2[i-1][y]);
				for(int x=1;x<=n;x++) for(int y=1;y<=n;y++) add(dp2[i][x],dp2l[i-1][y]*fr[i-1][x][y]%mod);
				for(int x=1;x<=n;x++) add(dp2[i][x],dp2l[i-1][x]);
			}
		}
		int ans=0;
		for(int i=max(bs,bt)+1;i<=k;i++) for(int x=1;x<=n;x++) add(ans,dp1r[i-1][x]*dp2l[i-1][x]%mod);
		if(bs==bt) add(ans,(s==t));
		if(bs<bt) add(ans,dp1r[bt-1][t]);
		if(bs>bt) add(ans,dp2l[bs-1][s]);
		cout<<ans<<"\n";
	}
	return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...