zoukankan      html  css  js  c++  java
  • hdu_5807_Keep In Touch(分段dp)

    题目链接:hdu_5807_Keep In Touch

    题意:

    在Byteland一共有nn个城市,编号依次为11到nn,同时有mm条单向道路连接着这些城市,其中第ii条道路的起点为u_iui​​,终点为v_i(1leq u_i < v_ileq n)vi​​(1ui​​<vi​​n)。
    
    特工团队一共有33名成员:007,008,以及009,他们将要执行qq次秘密任务。
    
    在每次任务中,三人可能会处于三个不同的城市,他们互相之间通过对讲机保持联络。编号为ii的城市的无线电频为w_iwi​​,如果两个城市的无线电频差值的绝对值不超过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
    ",dp[x][y][z][0]);
    33     }
    34     return 0;
    35 }
    View Code
  • 相关阅读:
    消失的 unittest.makeSuite()
    自定义错误信息在各个浏览器表现不同
    “创建Web应用程序”与“创建Web网站”的区别
    如何将Notepad++改造成Python开发工具
    64位服务器IIS不能识别32位framework版本。IIS没有Asp.net切换界面的解决办法。
    C++文件流,读入数据注意
    Chessboard(二分图完备匹配)
    courses二分图最大匹配
    Linux BASH Shell文件名匹配/输出重定向
    LinuxShell一些很少用到却很有用的指令
  • 原文地址:https://www.cnblogs.com/bin-gege/p/5747455.html
Copyright © 2011-2022 走看看