hdu_5807_Keep In Touch(分段dp)

题目链接:hdu_5807_Keep In Touch

题意:

在Byteland一共有nn个城市,编号依次为11到nn,同时有mm条单向道路连接着这些城市,其中第ii条道路的起点为u_iu?i??,终点为v_i(1\leq u_i < v_i\leq n)v?i??(1≤u?i??<v?i??≤n)。

特工团队一共有33名成员:007,008,以及009,他们将要执行qq次秘密任务。

在每次任务中,三人可能会处于三个不同的城市,他们互相之间通过对讲机保持联络。编号为ii的城市的无线电频为w_iw?i??,如果两个城市的无线电频差值的绝对值不超过KK,那么无线电就可以接通。三个特工每个时刻必须要选择一条道路,走到下一个城市,每条道路都只需要花费11单位时间。

他们可以选择在任意城市终止任务,甚至可以在起点就终止任务,但不允许在道路上终止任务。现在他们想知道,对于每次任务,给定三个人的起始位置,有多少种可能的合法行动方案,使得行动过程中任意在城市的时刻,他们都可以两两联络?

两个方案被视作不同当且仅当至少存在一个人在某一时刻所在的城市不同。

注意:33个特工必须同时结束任务。题解:

1004 Keep In Touch

考虑dp,设f[i][j][k]表示三个人分别在i,j,k时的方案数,直接转移是O(n^6)的。

于是考虑加维,设f[i][j][k][now]表示三个人分别在i,j,k,时,目前准备走now这个人的方案数,那么转移复杂度就降低到了O(n^4)。

这题的套路就是分段DP,朴素的同时转移会枚举三个点,所以会达到O(n6),

 1 #include<bits/stdc++.h>
 2 #define F(i,a,b) for(int i=a;i<=b;i++)
 3 using namespace std;
 4 typedef long long ll;
 5 const int N=50+7,mod=998244353;
 6
 7 int t,n,m,K,q,x,y,z,w[N],g[N][N],dp[N][N][N][3];
 8
 9 int main()
10 {
11     scanf("%d",&t);
12     while(t--)
13     {
14         scanf("%d%d%d%d",&n,&m,&K,&q);
15         F(i,1,n)scanf("%d",w+i);
16         memset(g,0,sizeof(g)),memset(dp,0,sizeof(dp));
17         F(i,1,m)scanf("%d%d",&x,&y),g[x][y]=1;
18         for(int i=n;i>=1;i--)
19             for(int j=n;j>=1;j--)
20                 for(int k=n;k>=1;k--)
21                 {
22                     if(abs(w[i]-w[j])<=K&&abs(w[i]-w[k])<=K&&abs(w[k]-w[j])<=K)
23                         (dp[i][j][k][0]+=1)%=mod;
24                     else dp[i][j][k][0]=0;
25                     if(dp[i][j][k][0])F(ii,1,i-1)if(g[ii][i])
26                         (dp[ii][j][k][2]+=dp[i][j][k][0])%=mod;
27                     if(dp[i][j][k][1])F(ii,1,j-1)if(g[ii][j])
28                         (dp[i][ii][k][0]+=dp[i][j][k][1])%=mod;
29                     if(dp[i][j][k][2])F(ii,1,k-1)if(g[ii][k])
30                         (dp[i][j][ii][1]+=dp[i][j][k][2])%=mod;
31                 }
32         while(q--)scanf("%d%d%d",&x,&y,&z),printf("%d\n",dp[x][y][z][0]);
33     }
34     return 0;
35 }

时间: 2024-10-07 05:30:06

hdu_5807_Keep In Touch(分段dp)的相关文章

HDU5807分段dp

DAG图. [题意] n(50)个城市m(c(n,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)出发,可以在合法状态中任意行走任意终止,有多少种不同的行走路径数 f[i][j][k] = ∑f[ii][jj][kk],ii,jj,kk分别为i,j,k的直接后继 时

HDU1024 经典DP+状态压缩

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1024 题目大意: 求n个数分成m个子区间的最大和 推导过程已写在代码中 #include <stdio.h> #include <algorithm> #include <string.h> using namespace std; #define oo 0x3f3f3f3f int dp[1000010], maxn[1000010], nums[1000010]; /

2017多校Round3(hdu6056~hdu6066)

补题进度:7/11 1001 待填坑 1002 待填坑 1003(set) 题意: 给定长度为n(n<=5e5)的数组(是n的一个排列)和一个整数k(k<=80),f[l,r]定义为区间[l,r]内的第k大的数,求所有区间的f值的和 分析: 倒过来考虑,考虑每个数a[i]对答案有多少贡献 将n个数字从大到小依次插入对应位置,已经插入的当作障碍点(可以用set来维护) 那么对于一个i,可以枚举其左边有x个右边有k-x个去统计答案,因为k<=80,所以是OK的 注意边界情况 时间复杂度O(n

cf # 420 div.2

说说题吧前两道暴力 a直接枚举每个位置然后枚举所在行和列 b直接枚举所有的x的banana 的数量.计算方式等差数列求和小学生难度.记得long long.int转longlong c记下remove的次数,add直接入栈,remove看栈顶是正确的就出,空栈就出堆顶,不正确就全部入堆ans++ d给每个k和所在行和列的每个点建一条长为1的边,和一条长度为0的回边.求最短路 e据说是分段dp,留坑 sb我依然只写了2道

湖南多校对抗赛(2015.03.28) E Longest Increasing Subsequence Again

题意:给你一个序列,问你删除掉连续的一段,使得剩下的序列的最长上升字串最大,问你这个最大值. 解题思路:分段dp,  dp[i][0] ,dp[i][1]   , 0表示前面没有切过,只能从前一个数的0状态得到,1状态表示前面已经切过了,能从前一个的1状态得到,也能从 在他前面的比他值小的dp[j][0](j < i && a[j] < a[i])的最大值得到,这里用线段树维护就行了. 解题代码: 1 // File Name: b.cpp 2 // Author: darkd

HDU 5807 Keep In Touch DP

Keep In Touch Problem Description There are n cities numbered with successive integers from 1 to n in Byteland. Also, there are m one-way roads connecting the cities. The starting point of the i-th road is ui while the ending point is vi. There are 3

UVALive - 6952 DP 分段/隔板

题意:商品总价按四舍五入计算,n个物品最多可分\(d+1\)段,求最小代价 \(dp[i][j]\):\(j\)个物品分\(i\)段 注意一个技巧是只在需要分出新的段时才四舍五入(旧段结算),这样就避免了不知道分段具体位置无法\(dp\)的情况 数据量比较小就不使用滚动数组了 #include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<cstdli

[HDU5807] [BestCoder Round #86 1004] Keep In Touch (DP)

[HDU5807] [BestCoder Round #86 1004] Keep In Touch (DP) 题面 有三个人从一张N个点无重边的有向无环图上的三个点出发,每单位时间,他们分别选择当前点的一条出边走下去.有向无环图点有点权,任意时刻他们所在的三个点两两点权相差不超过K.他们可以在任意三个点同时结束.求合法的路径总数.N≤50. 分析 暴力的做法,设\(dp[i][j][k]\)表示第一个人在i,第二个人在j,第三个人在k的方案数,然后枚举三个人接着到的地方x,y,z,倒推\(dp

HDU5807 Keep In Touch (BestCoder Round #86 D ) 分布式dp

#include <cstdio> #include <cstring> #include <cmath> #include <vector> #include <algorithm> using namespace std; typedef long long LL; const int N = 50+2; const int mod = 998244353; int T,n,m,lim,q,tot,w[N],dp[N][N][N][3],he