• 都市环游



    【问题描述】
    因为 SJY 干的奇怪事情过多,SJY 收到了休假的通知,于是他准备在都市间
    来回旅游。SJY 有一辆车子,一开始行驶性能为 0,每过 1 时间行驶性能就会提
    升 1 点。每个城市的道路都有性能要求。SJY 一共有 t 时间休息,一开始他位于
    1 号城市(保证 1 号城市道路要求为 0),他希望在 n 号城市结束旅程。每次穿过
    一条城市间的路会花费 1 时间, 当然他也可以停留在一个城市不动而花费 1 时间。
    当且仅当车子的行驶性能大于等于一个城市, 我们才能到达那里。 SJY 希望知道,
    旅游的方案模 10086 后的答案。(只要在某一时刻通过的道路存在一条不相同,
    就算不同的方案)
    【输入】
    第一行三个数 n,m,t,表示有 n 个城市 m 条道路 t 时间。
    第二行 n 个数,hi 表示第 i 个城市的道路性能要求。
    第三到 m+2 行,每行两个数 u,v,表示城市 u 与城市 v 之间有一条单向道路
    连接(可能有重边)。
    【输出】
    包括一个数字,表示旅游的方案模 10086。
    【输入输出样例】
    travel.in travel.out
    5 17 7
    0 2 4 5 3
    1 2
    2 1
    1 3
    3 1
    1 4
    4 1
    4 5
    5 4
    5 3
    4 1
    2 1
    5 3
    2 1
    2 1
    1 2
    2 1
    1 3
    245
    第 5 页 共 6 页
    【数据规模和约定】
    对于 20%的数据,n<=10,t<=80;
    对于 50%的数据,n<=30,t<=80;
    对于 100%的数据,n<=70,m<=1000,t<=100000000,hi<=70。

    题解:
      首先一个二维的dp就可以搞出来,就是设dp[i][j],表示处于i节点,已经用了j天的方案数,转移十分显然,能否走或者停留到原点,所以dp[i][j]=dp[i][j-1],dp[i][j]+=dp[to][j-1],这个to,是反边的儿子节点,就是说可以从to转移到i来。这个只能有50分,记忆化搜索跑的十分快。

      但我们注意到t太大了,根本开不下,所以我们思考,因为城市的限制很小,所以一旦大于71,后面的转移就不用考虑车子了,所以前面的71可以用dp处理出来,后面的我们可以用矩阵快速幂来优化。

      首先,初始矩阵s[i][j],表示第72天i到j的方案数,然后转移矩阵k[i][j],表示i~j的路径数,然后乘起来就对了,但为什么是对的呢?其实本质就是一个floyed和乘法原理求方案数。

    代码:

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    #include <iostream>
    #define MAXN 100
    #define mod 10086
    #define MAXN2 1000000
    using namespace std;
    struct zhen{
        int w[MAXN][MAXN];
        zhen(){
            memset(w,0,sizeof(w));
        }
    };
    int c[MAXN][MAXN],ask[MAXN],dp[MAXN][MAXN];
    int n,m,t;
    
    void work(){
        dp[1][0]=1;
        for(int t=0;t<=80;t++)
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    if(t+1>=ask[j])
                        dp[j][t+1]+=dp[i][t]*c[i][j],dp[j][t+1]%=mod;
        return;
    }
    
    zhen jvchen(zhen x,zhen y){
        zhen z;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                for(int k=1;k<=n;k++)
                    z.w[i][j]+=x.w[i][k]*y.w[k][j],z.w[i][j]%=mod;
        return z;
    }
    
    
    int main(){
        scanf("%d%d%d",&n,&m,&t);
        for(int i=1;i<=n;i++) scanf("%d",&ask[i]),c[i][i]++;
        for(int i=1;i<=m;i++){
            int x,y;scanf("%d%d",&x,&y);
            c[x][y]++;
        }
        work();
        if(t<=79){
            printf("%d",dp[n][t]);
            return 0;
        }
        zhen star,zhuan;
        for(int i=1;i<=n;i++){
            star.w[i][i]=dp[i][80];
            for(int j=1;j<=n;j++)
                zhuan.w[i][j]=c[i][j];
        }
        t-=80;
        while(t){
            if(t&1) star=jvchen(star,zhuan);
            zhuan=jvchen(zhuan,zhuan);t>>=1;
        }
        int ans=0;
        for(int i=1;i<=n;i++) ans+=star.w[i][n],ans%=mod;
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    曾经写的一些文章,与技术无关,整理出来怀旧,:)
    在VS.NET2003中使用XHTML的插件HTML TIDY 及 MindManger
    把机器退出了域,造成无法启动 MSSQLSERVER ,晕
    hello php!
    今天又看了一下存储过程
    [转]PAGEII携手极速网爱情电影经典对白
    关键词:2005年,世乒赛.上海,乒乓的胜地
    一本SharePoint方面的书,Special Edition Using Microsoft® SharePoint Portal Server
    keo计划
    关于xp_cmdshell 。。注意安全!
  • 原文地址:https://www.cnblogs.com/renjianshige/p/7384514.html
Copyright © 2020-2023  润新知