Keep In Touch
题目链接:点我打开链接
题意:有n个城市,编号依次为1$到n,同时有m条单向道路连接着这些城市,其中第i条道路的起点为Ui,终点为Vi 。(1<=Ui < Vi <= n)。
特工团队一共有3名成员:007,008,以及009,他们将要执行q次秘密任务。
在每次任务中,三人可能会处于三个不同的城市,他们互相之间通过对讲机保持联络。编号为i的城市的无线电频为Wi,如果两个城市的无线电频差值的绝对值不超过K,那么无线电就可以接通。三个特工每个时刻必须要选择一条道路,走到下一个城市,每条道路都只需要花费1单位时间。
他们可以选择在任意城市终止任务,甚至可以在起点就终止任务,但不允许在道路上终止任务。现在他们想知道,对于每次任务,给定三个人的起始位置,有多少种可能的合法行动方案,使得行动过程中任意在城市的时刻,他们都可以两两联络?
两个方案被视作不同当且仅当至少存在一个人在某一时刻所在的城市不同。
特工团队一共有3名成员:007,008,以及009,他们将要执行q次秘密任务。
在每次任务中,三人可能会处于三个不同的城市,他们互相之间通过对讲机保持联络。编号为i的城市的无线电频为Wi,如果两个城市的无线电频差值的绝对值不超过K,那么无线电就可以接通。三个特工每个时刻必须要选择一条道路,走到下一个城市,每条道路都只需要花费1单位时间。
他们可以选择在任意城市终止任务,甚至可以在起点就终止任务,但不允许在道路上终止任务。现在他们想知道,对于每次任务,给定三个人的起始位置,有多少种可能的合法行动方案,使得行动过程中任意在城市的时刻,他们都可以两两联络?
两个方案被视作不同当且仅当至少存在一个人在某一时刻所在的城市不同。
注意:3个特工必须同时结束任务。
简单地说,有n( 0<=n<=50 )个城市m ( 0<=m<=n*(n-1)/2 ) 条单向边(x,y),保证x<y 。
对于三个点(x,y,z)如果abs(w[x]-w[y])<=K && abs(w[x]-w[y])<=K && abs(w[x]-w[y])<=K则就是一个合法状态。 否则就不合法。
问你,如果我们从(x,y,z)出发,可以在合法状态中任意行走任意终止,有多少种不同的行走路径数。
对于三个点(x,y,z)如果abs(w[x]-w[y])<=K && abs(w[x]-w[y])<=K && abs(w[x]-w[y])<=K则就是一个合法状态。 否则就不合法。
问你,如果我们从(x,y,z)出发,可以在合法状态中任意行走任意终止,有多少种不同的行走路径数。
官方题解:考虑dp,设f[ i ][ j ][ k ]表示三个人分别在 i , j , k时的方案数,直接转移是O(n^6)的。 于是考虑加维,设f[i][j][k][now]表示三个人分别在i,j,k时,目前准备走now这个人的方案数,那么转移复杂度就降低到了O(n^4)。
我用的是三维。但本质不变。
AC代码:(三维)
//#include<bits/stdc++.h>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<map>
#include<queue>
#include<set>
#include<stack>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N = 50+10;
const int mod=998244353;
int MAX[3];
int MAXN[3];
int read()
{
int v = 0, f = 1;
char c =getchar();
while( c < 48 || 57 < c ){
if(c=='-') f = -1;
c = getchar();
}
while(48 <= c && c <= 57)
v = v*10+c-48, c = getchar();
return v*f;
}
ll dp[N][N][N];
int a[N][N];
int w[N];
int g[N][N][N];
int h[N][N][N];
int main()
{
// freopen("in.txt","r",stdin);
int t,n,m,k,q;
int x,y,z;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d%d",&n,&m,&k,&q);
for(int i=1;i<=n;i++) scanf("%d",&w[i]);
memset(a,0,sizeof(a));
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
a[y][x]=1;
}
for(int i=n;i>=1;--i)
for(int j=n;j>=1;--j)
for(int d=n;d>=1;--d){
dp[i][j][d] = 1;g[i][j][d] = 0;h[i][j][d] = 0;
for(int t=1;t<=n;t++){
if(a[t][i]){
( dp[i][j][d] += h[t][j][d]) %=mod;
}
}
for(int t=1;t<=n;t++){
if(a[t][j]){
( h[i][j][d] += g[i][t][d] )%=mod;
}
}
for(int t=1;t<=n;t++){
if(a[t][d]){
( g[i][j][d] += dp[i][j][t])%=mod;
}
}
//不合法
if(abs(w[i]-w[j]) > k) dp[i][j][d] = 0;
if(abs(w[i]-w[d]) > k) dp[i][j][d] = 0;
if(abs(w[j]-w[d]) > k) dp[i][j][d] = 0;
}
for(int i=1;i<=q;i++)
{
scanf("%d%d%d",&x,&y,&z);
printf("%lld\n",dp[x][y][z]);
}
}
return 0;
}
代码:
//#include<bits/stdc++.h>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<map>
#include<queue>
#include<set>
#include<stack>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N = 50+10;
const int mod=998244353;
int t;
int n, m, K, q;
int w[N];
vector<int>a[N];
int f[N][N][N][3];
bool e[N][N];
int main()
{
// freopen("in.txt","r",stdin);
scanf("%d", &t);
for (int i = 1; i <= t; i++)
{
memset(e,0,sizeof(e));
scanf("%d%d%d%d", &n, &m, &K, &q);
for (int i = 1; i <= n; ++i)scanf("%d", &w[i]), a[i].clear();
for (int i = 1; i <= m; ++i)
{
int x, y; scanf("%d%d", &x, &y);
a[y].push_back(x);
e[x][y] = 1;
}
memset(f,0,sizeof(f));
for (int i = n; i >= 1; --i)
{
for (int j = n; j >= 1; --j)
{
for (int k = n; k >= 1; --k)
{
if (abs(w[i] - w[j]) > K || abs(w[i] - w[k]) > K || abs(w[j] - w[k]) > K)
f[i][j][k][0] = 0;
else (f[i][j][k][0]+=1)%=mod;
if (f[i][j][k][0])
for (int u = 1; u < i; ++u)
if (e[u][i])
(f[u][j][k][2]+=f[i][j][k][0])%=mod;
if(f[i][j][k][1])
for (int u = 1; u < k; ++u)
if (e[u][k])
(f[i][j][u][0]+=f[i][j][k][1])%=mod;
if(f[i][j][k][2])
for (int u = 1; u < j; ++u)
if (e[u][j])
(f[i][u][k][1]+=f[i][j][k][2])%=mod;
}
}
}
while (q--)
{
int x, y, z;
scanf("%d%d%d", &x, &y, &z);
printf("%d\n", f[x][y][z][0]);
}
}
return 0;
}