HDU5807分段dp

DAG图。

  1. 【题意】
  2. n(50)个城市m(c(n,2))条单向边(x,y),保证x<y
  3. 对于三个点(x,y,z)如果abs(w[x]-w[y])<=K && abs(w[x]-w[y])<=K && abs(w[x]-w[y])<=K则这是一个合法状态。
  4. 问你,如果我们从(x,y,z)出发,可以在合法状态中任意行走任意终止,有多少种不同的行走路径数

f[i][j][k] = ∑f[ii][jj][kk],ii,jj,kk分别为i,j,k的直接后继

时间复杂度是O(n^6)的,需要优化。

另开一维枚举当前要走的人。

我们假定先走k,再走j,最后走i,目前在i,j,k。

f[i][j][k][0]表示k,j,i走完下一轮继续走k,j,i的方案数f[u][j][k][2] += f[i][j][k][0];

f[i][j][k][1]表示k走完下一步走j,再走i的方案数f[i][u][k][1] += f[i][j][k][2];

f[i][j][k][2]表示k,j走完下一步走i的方案数f[i][j][u][0] += f[i][j][k][1];

倒着dp

  1. 具体转移是这样子的——
  2. if (!ok(i, j) || !ok(i, k) || !ok(j, k))f[i][j][k][0] = 0;
  3. else gadd(f[i][j][k][0], 1);
  4. //这个DP的起点条件并不一定是要满足ok(i,j)&&ok(i,k)&&ok(j,k),因为这个状态可能是中途状态
  5. if (f[i][j][k][0])
  6. for (int u = 1; u < i; ++u)if (e[u][i])
  7. gadd(f[u][j][k][2], f[i][j][k][0]);
  8. if(f[i][j][k][2])
  9. for (int u = 1; u < j; ++u)if (e[u][j])
  10. gadd(f[i][u][k][1], f[i][j][k][2]);
  11. if(f[i][j][k][1])
  12. for (int u = 1; u < k; ++u)if (e[u][k])
  13. gadd(f[i][j][u][0], f[i][j][k][1]);
  1. 【题意】
  2. n(50)个城市m(c(n,2))条单向边(x,y),保证x<y
  3. 对于三个点(x,y,z)如果abs(w[x]-w[y])<=K && abs(w[x]-w[y])<=K && abs(w[x]-w[y])<=K则这是一个合法状态。
  4. 问你,如果我们从(x,y,z)出发,可以在合法状态中任意行走任意终止,有多少种不同的行走路径数
  5. 【类型】
  6. 分段式DP 打破题目约束
  7. 【分析】
  8. 这道题可以AC的复杂度最多只能为O(n^4)
  9. 而一个状态是O(n^3),如果我们暴力枚举两个状态,并做转移,复杂度是O(n^6)的。
  10. 于是我们要尝试优化——
  11. 我们发现,我们在转移的时候,可以考虑的不再是三重循环转移,而是分步式转移。
  12. 即,虽然题目要求是三个人同时走,但是我们可以把其转化为三个人轮流走的情况。
  13. 因为同时走的复杂度是是要做三种枚举。所以我们定义状态的一二三步
  14. 即f[i][j][k][0]表示,下一步是i走
  15. 即f[i][j][k][1]表示,下一步是j走
  16. 即f[i][j][k][2]表示,下一步是k走
  17. 这样答案的输出是f[i][j][k][0],这时三个人步长相同。
  18. 因为我们计算的时候,按照基本转移方程,f[i][j][k]+=f[ii][jj][kk],(ii,jj,kk)是(i,j,k)的合法后继
  19. 所以,(i,j,k)较大的要先算出来。于是我们倒着展开DP。
  20. 具体转移是这样子的——
  21. if (!ok(i, j) || !ok(i, k) || !ok(j, k))f[i][j][k][0] = 0;
  22. else gadd(f[i][j][k][0], 1);
  23. //这个DP的起点条件并不一定是要满足ok(i,j)&&ok(i,k)&&ok(j,k),因为这个状态可能是中途状态
  24. if (f[i][j][k][0])
  25. for (int u = 1; u < i; ++u)if (e[u][i])
  26. gadd(f[u][j][k][2], f[i][j][k][0]);
  27. if(f[i][j][k][2])
  28. for (int u = 1; u < j; ++u)if (e[u][j])
  29. gadd(f[i][u][k][1], f[i][j][k][2]);
  30. if(f[i][j][k][1])
  31. for (int u = 1; u < k; ++u)if (e[u][k])
  32. gadd(f[i][j][u][0], f[i][j][k][1]);
  33. 【时间复杂度&&优化】
  34. O(n^4)
时间: 2024-10-07 01:19:38

HDU5807分段dp的相关文章

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_

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

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

poj 2479 dp求分段最大和

Maximum sum Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 38079   Accepted: 11904 Description Given a set of n integers: A={a1, a2,..., an}, we define a function d(A) as below: Your task is to calculate d(A). Input The input consists o