思路:完全看着别人的代码才知道的思路,感觉这种方法很神奇,所以自己想写一下。
如BC题解所写,O(n^6)的时间复杂度过高,用加维的方法解决,因为题目里写着:“三个特工每个时刻必须要选择一条道路,走到下一个城市”,所以三个特工的移动是连续的。所以可以规定先移动第一个特工再移动第二个特工,然后是第三个,不断循环,用dp预处理好所有的答案。(代码中为了节约空间,把三个特工的代号规定为0,1,2)
规定最开始先移动0号特工,则到了0号特工要移动时,每个特工的所处位置必须合法,此时必须检查各点是否两两相连,才可以接着进行dp。
…………访问量这么少,我已经写不动了…………
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MS(x,y) memset(x,y,sizeof(x))
typedef long long LL;
const int MAXN=55;
const int MAXM=MAXN*MAXN/2;
const int MOD=998244353;
int val[MAXN];
LL dp[MAXN][MAXN][MAXN][3];
struct Edge{
int v,nxt;
}edge[MAXM];
int head[MAXN],edgenum;
void addedge(int u,int v){
edge[edgenum].v=v;
edge[edgenum].nxt=head[u];
head[u]=edgenum++;
}
int main(){
int T;
scanf("%d",&T);
int n,m,K,q;
while(T--){
scanf("%d%d%d%d",&n,&m,&K,&q);
for(int i=1;i<=n;++i) scanf("%d",val+i);
edgenum=0;
MS(head,-1);
MS(dp,0);
int u,v;
while(m--){
scanf("%d%d",&u,&v);
addedge(v,u);
}
for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) for(int k=1;k<=n;++k)
if(abs(val[i]-val[j])<=K&&abs(val[i]-val[k])<=K&&abs(val[j]-val[k])<=K)
dp[i][j][k][0]=1;
for(int i=n;i;--i) for(int j=n;j;--j) for(int k=n;k;--k){
int v;
for(int e=head[i];~e;e=edge[e].nxt){
v=edge[e].v;
(dp[v][j][k][1]+=dp[i][j][k][0])%=MOD;
}
for(int e=head[j];~e;e=edge[e].nxt){
v=edge[e].v;
(dp[i][v][k][2]+=dp[i][j][k][1])%=MOD;
}
for(int e=head[k];~e;e=edge[e].nxt){
v=edge[e].v;
if(abs(val[i]-val[j])<=K&&abs(val[i]-val[v])<=K&&abs(val[j]-val[v])<=K)
(dp[i][j][v][0]+=dp[i][j][k][2])%=MOD;
}
}
while(q--){
scanf("%d%d%d",&u,&v,&m);
printf("%I64d\n",dp[u][v][m][0]);
}
}
}