[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[i][j][k]=\sum dp[x][y][z]\)。这样的时间复杂度是\(O(n^6)\)

注意到我们没必要每次让三个人一起走,只要分三次走就可以了。给dp再加一维,\(dp[i][j][k][0/1/2]\)分别表示轮到第1个人走(初始状态),第2个人走,第3个人走。然后由2转移到0,0转移到1,1转移到2即可。这样的时间复杂度是\(O(n^4)\)

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 50
#define mod 998244353
using namespace std;
int t,n,lim,m,q;
int w[maxn+5];
int g[maxn+5][maxn+5];
int dp[maxn+5][maxn+5][maxn+5][3];
void ini(){
    memset(g,0,sizeof(g));
    memset(dp,0,sizeof(dp));
}
int main(){
    int u,v,a,b,c;
    scanf("%d",&t);
    for(int cas=1;cas<=t;cas++){
        ini();
        scanf("%d %d %d %d",&n,&m,&lim,&q);
        for(int i=1;i<=n;i++) scanf("%d",&w[i]);
        for(int i=1;i<=m;i++){
            scanf("%d %d",&u,&v);
            g[u][v]=1;
        }
        for(int i=n;i>=1;i--){//题目要求u<v,所以倒推
            for(int j=n;j>=1;j--){
                for(int k=n;k>=1;k--){
                    dp[i][j][k][0]=1;
                    dp[i][j][k][1]=0;
                    dp[i][j][k][2]=0;
                    for(int u=i+1;u<=n;u++){
                        if(g[i][u]){
                            dp[i][j][k][0]+=dp[u][j][k][2];
                            dp[i][j][k][0]%=mod;
                        }
                    }
                    for(int u=j+1;u<=n;u++){
                        if(g[j][u]){
                            dp[i][j][k][1]+=dp[i][u][k][0];
                            dp[i][j][k][1]%=mod;
                        }
                    }
                    for(int u=k+1;u<=n;u++){
                        if(g[k][u]){
                            dp[i][j][k][2]+=dp[i][j][u][1];
                            dp[i][j][k][2]%=mod;
                        }
                    }
                    if(max(max(abs(w[i]-w[j]),abs(w[i]-w[k])),abs(w[j]-w[k]))>lim) dp[i][j][k][0]=0;
                }
            }
        }
        for(int i=1;i<=q;i++){
            scanf("%d %d %d",&a,&b,&c);
            printf("%d\n",dp[a][b][c][0]);
        }
    }
}

原文地址:https://www.cnblogs.com/birchtree/p/11244032.html

时间: 2024-12-09 19:01:04

[HDU5807] [BestCoder Round #86 1004] Keep In Touch (DP)的相关文章

HDU 5806 NanoApe Loves Sequence Ⅱ(尺取+思维)——BestCoder Round #86 1003

传送门 NanoApe Loves Sequence Ⅱ Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/131072 K (Java/Others)Total Submission(s): 514    Accepted Submission(s): 248 Problem Description NanoApe, the Retired Dog, has returned back to prepare for f

BestCoder Round #75 King&amp;#39;s Order dp:数位dp

King's Order Accepts: 381 Submissions: 1361 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Problem Description After the king's speech , everyone is encouraged. But the war is not over. The king needs to give orders

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

BestCoder Round #86 解题报告

A.Price List Sol 求和查询 Code #include<cstdio> #include<algorithm> #include<iostream> using namespace std; typedef long long LL; const int N = 100005; //LL v[N]; inline LL in(LL x=0,char ch=getchar()){ while(ch>'9'||ch<'0') ch=getchar

HDU5808Price List Strike Back (BestCoder Round #86 E) cdq分治+背包

严格按题解写,看能不能形成sum,只需要分割当前sum怎么由两边组成就好 #include <cstdio> #include <cstring> #include <cmath> #include <vector> #include <algorithm> using namespace std; const int INF = 0x3f3f3f3f; const int N = 2e4+100; int f[N][105],g[N][105]

HDU5806 NanoApe Loves Sequence Ⅱ (BestCoder Round #86 C)二分

分析:大于等于m的变成1,否则变成0,预处理前缀和,枚举起点,找到第一个点前缀和大于m即可 找第一个点可以二分可以尺取 #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; typedef long long LL; const int N = 2e5+5; int T,n,m,k,a[N],sum[N]; int mai

HDU5804 Price List (BestCoder Round #86 A)水题

分析:大于总和输出1 #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long LL; const int N = 1e5+5; int ret[N],T,n,m; int main(){ scanf("%d",&T); while(T--){ scanf("%d%d",&n,&a

BestCoder Round #86 1001

链接http://acm.hdu.edu.cn/showproblem.php?pid=5804 题意:给你一些商店和他的商品价格,然后给你一个记账本,问你记大了就是1,否则是0 解法:模拟,注意测试数据大小 #include<stdio.h> //#include<bits/stdc++.h> #include<string.h> #include<iostream> #include<math.h> #include<sstream&g

BestCoder Round #86 二,三题题解(尺取法)

第一题太水,跳过了. NanoApe Loves Sequence题目描述:退役狗 NanoApe 滚回去学文化课啦! 在数学课上,NanoApe 心痒痒又玩起了数列.他在纸上随便写了一个长度为 nnn 的数列,他又根据心情随便删了一个数,这样他得到了一个新的数列,然后他计算出了所有相邻两数的差的绝对值的最大值. 他当然知道这个最大值会随着他删了的数改变而改变,所以他想知道假如全部数被删除的概率是相等的话,差的绝对值的最大值的期望是多少. 输入描述 第一行为一个正整数 T,表示数据组数. 每组数