zoukankan      html  css  js  c++  java
  • HDU5807 Keep In Touch(分段式dp)

    题意:

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

    其中第i条道路的起点为ui​​,终点为vi(1≤u​i​​<v​i​​≤n)。 特工团队一共有3名成员:007008,以及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
    ",dp[x][y][m][0]);
            }
        }
        return 0;
    }
  • 相关阅读:
    sudo命令 sudoers文件
    sscanf函数
    printf格式化输出
    c文件操作
    string和char*
    c去除空格 小写转大写
    主机序和网络序转换
    ulimit用法
    mysql基础(附具体操作代码)
    ES6 class
  • 原文地址:https://www.cnblogs.com/d-e-v-i-l/p/5746496.html
Copyright © 2011-2022 走看看