HDU5807 Keep In Touch(分段式dp)

题意:

在Byteland一共有n个城市,编号依次为1到n,同时有m条单向道路连接着这些城市,

其中第i条道路的起点为ui??,终点为vi(1≤u?i??<v?i??≤n)。

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

在每次任务中,三人可能会处于三个不同的城市,他们互相之间通过对讲机保持联络。

编号为i的城市的无线电频为w?i??,如果两个城市的无线电频差值的绝对值不超过K,

那么无线电就可以接通。三个特工每个时刻必须要选择一条道路,走到下一个城市,每条道路都只需要花费1单位时间。

他们可以选择在任意城市终止任务,甚至可以在起点就终止任务,但不允许在道路上终止任务。现在他们想知道,

对于每次任务,给定三个人的起始位置,有多少种可能的合法行动方案,使得行动过程中任意在城市的时刻,他们都可以两两联络?

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

注意:3个特工必须同时结束任务。

思路:

这题乍一看就是O(n^6)的时间复杂度,由于最后也没想出来什么好做法,就写了一发。。果断被hack- -

正解是将三人同时走转化为一个一个地走,加一维,

dp[i][j][l][p]表示三个人分别在i,j,l时,目前准备走p这个人的方案数,这样就是O(n^4)的了

/* ***********************************************
Author        :devil
************************************************ */
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <stdlib.h>
using namespace std;
typedef long long LL;
const int inf=0x3f3f3f3f;
const int mod=998244353;
const int N=51;
int dp[N][N][N][3],w[N];
bool mp[N][N];
int main()
{
    //freopen("in.txt","r",stdin);
    int t,n,m,k,q,x,y;
    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(mp,0,sizeof(mp));
        while(m--)
        {
            scanf("%d%d",&x,&y);
            mp[x][y]=1;
        }
        memset(dp,0,sizeof(dp));
        for(int i=n;i>=1;i--)
        {
            for(int j=n;j>=1;j--)
            {
                for(int l=n;l>=1;l--)
                {
                    if(abs(w[i]-w[j])>k||abs(w[i]-w[l])>k||abs(w[j]-w[l])>k) dp[i][j][l][0]=0;
                    else dp[i][j][l][0]=(dp[i][j][l][0]+1)%mod;
                    if(dp[i][j][l][0])
                        for(int p=1;p<l;p++)
                            if(mp[p][l])
                                dp[i][j][p][2]=(dp[i][j][p][2]+dp[i][j][l][0])%mod;
                    if(dp[i][j][l][2])
                        for(int p=1;p<j;p++)
                            if(mp[p][j])
                                dp[i][p][l][1]=(dp[i][p][l][1]+dp[i][j][l][2])%mod;
                    if(dp[i][j][l][1])
                        for(int p=1;p<i;p++)
                            if(mp[p][i])
                                dp[p][j][l][0]=(dp[p][j][l][0]+dp[i][j][l][1])%mod;
                }
            }
        }
        while(q--)
        {
            scanf("%d%d%d",&x,&y,&m);
            printf("%d\n",dp[x][y][m][0]);
        }
    }
    return 0;
}
时间: 2024-10-11 10:52:54

HDU5807 Keep In Touch(分段式dp)的相关文章

超酷创意分段式SVG文字动画特效

这是一款基于segment.js制作的非常有创意的分段式SVG文字动画特效.这个文字动画特效通过动画SVG的描边路径来制作各种文字的动画效果,效果非常的赞. 这个SVG文字动画特效的第一个DEMO中的最后几个例子使用了mo.js插件,一款由Oleg Solomka编写的用于制作网页图形动画的JavaScript库插件.通过mo.js,可以制作出效果更为震撼的文字动画效果. 在线预览   源码下载 特效中使用的字体是exquisite lowercase font,一套极富创意的WEB字体. 使用

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

openjudge6047分蛋糕[DP]

描述 有一块矩形大蛋糕,长和宽分别是整数w .h.现要将其切成m块小蛋糕,每个小蛋糕都必须是矩形.且长和宽均为整数.切蛋糕时,每次切一块蛋糕,将其分成两个矩形蛋糕.请计算:最后得到的m块小蛋糕中,最大的那块蛋糕的面积下限. 假设w= 4, h= 4, m= 4,则下面的切法可使得其中最大蛋糕块的面积最小. 假设w= 4, h= 4, m= 3,则下面的切法会使得其中最大蛋糕块的面积最小: 输入共有多行,每行表示一个测试案例.每行是三个用空格分开的整数w, h, m ,其中1 ≤ w, h, m

分水果 DP(2015年 JXNU_ACS 算法组暑假第一次周赛)

分水果 Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other) Total Submission(s) : 16   Accepted Submission(s) : 7 Font: Times New Roman | Verdana | Georgia Font Size: ← → Problem Description 给定n个水果,每个水果都有一个重量,分成两堆,怎么分才使得分得的重量

操作系统之分段式内存管理1

1.分页操作系统的缺点? 1)页表太大,我们用多级页表克服了. 2)多级页表速度慢,我们用TLB翻译快表解决了绝大部分. 3)页面来回更换所带来的缺页中断的问题,我们用各类页面更换算法解决了大部分. 4)内部碎片相对于交换系统的外部碎片,还是可以忍受的. 最大的缺陷是:共享困难. 2.分段管理系统? 3.逻辑分段的优缺点? 1)每个逻辑单元可以单独占用一个虚拟地址空间,使得编写程序的空间大为增加. 2)段是按逻辑关系分的,共享变的方便. 3)不同的逻辑段使用不同的基址和极限,我们可以对不同的段采

【PAT甲级】1045 Favorite Color Stripe (30 分)(DP)

题意: 输入一个正整数N(<=200),代表颜色总数,接下来输入一个正整数M(<=200),代表喜爱的颜色数量,接着输入M个正整数表示喜爱颜色的编号(同一颜色不会出现两次),接下来输入一个正整数L(<=10000),代表条带的长度,接着输入L个正整数表示条带上的颜色的编号.输出以喜爱颜色顺序排列的最长子串长度(不必每种颜色都有,只保证相对位置相同,同种颜色可连续). 代码: #define HAVE_STRUCT_TIMESPEC#include<bits/stdc++.h>

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的直接后继 时

DP总结 ——QPH

常见优化 单调队列 形式 dp[i]=min{f(k)} dp[i]=max{f(k)} 要求 f(k)是关于k的函数 k的范围和i有关 转移方法 维护一个单调递增(减)的队列,可以在两头弹出元素,一头压入元素. 队列中维护的是两个值.一个是位置,这和k的范围有关系,另外一个是f(k)的值,这个用来维护单调性,当然如果f(k)的值可以利用dp值在O(1)的时间内计算出来的话队列中可以只维护一个表示位置的变量. 枚举到一个i的时候,首先判断队首元素的位置是否已经不满足k的范围了,如果不满足就将队首

CodeForces 268D a nice dp

//先贴一发错误的代码,dp[层数][方向] //因为是对不完整的方案计数了... 1 #include "iostream" 2 #include "cstdio" 3 #include "cstring" 4 #include "algorithm" 5 using namespace std; 6 const __int64 mod = 1e9 + 9; 7 __int64 dp[1010][5]; 8 int n, h