zoukankan      html  css  js  c++  java
  • HH去散步[SDOI2009]

    题目描述

    HH有个一成不变的习惯,喜欢饭后百步走。所谓百步走,就是散步,就是在一定的时间 内,走过一定的距离。 但是同时HH又是个喜欢变化的人,所以他不会立刻沿着刚刚走来的路走回。 又因为HH是个喜欢变化的人,所以他每天走过的路径都不完全一样,他想知道他究竟有多 少种散步的方法。 现在给你学校的地图(假设每条路的长度都是一样的都是1),问长度为t,从给定地 点A走到给定地点B共有多少条符合条件的路径

    输入

    第一行:五个整数N,M,t,A,B。
    N表示学校里的路口的个数
    M表示学校里的 路的条数
    t表示HH想要散步的距离
    A表示散步的出发点
    B则表示散步的终点。
    接下来M行
    每行一组Ai,Bi,表示从路口Ai到路口Bi有一条路。
    数据保证Ai != Bi,但不保证任意两个路口之间至多只有一条路相连接。 
    路口编号从0到N -1。 
    同一行内所有数据均由一个空格隔开,行首行尾没有多余空格。没有多余空行。 
    答案模45989。
    N ≤ 20,M ≤ 60,t ≤ 2^30,0 ≤ A,B

    输出

    一行,表示答案。

    样例输入

    4 5 3 0 0
    0 1
    0 2
    0 3
    2 1
    3 2

    样例输出

    4

    题解
        考试的时候想得比较粗略,一开始当然是暴力深搜,也知道这种方案数还取模的题不可能深搜出正解,但还是先打了一通,没费什么力气就出了样例。之后开始想正解,感觉或许应该把环收缩一下,但是环环相扣环环重叠不知道应该怎么处理,最后还是把深搜交上去了。
        正解是矩阵优化dp(但总感觉它其实说不上是dp),比如矩阵G[i,j]的k次方中的g(a,b)可以表示从a点到b点经过k条边的方案数,本题因为对于边有特殊的要求(不立刻反向)所以把边放进矩阵,G[i,j]为1表示从i到j有一条边,这里的边是分方向的,双向建边就会有2*m条。tot矩阵(其实只有一行)表示从起点有哪些边出来。tot乘上G[i,j]的k-1次方(注意顺序,矩阵乘法不满足交换律),把得到的一行结果矩阵中有边到终点的位加和,得到的结果即为答案。
        刚开始觉得矩阵非常抽象,虽然自己在课下学过很多数学书上的理论知识但还是不会用,不过这道题让我明白矩阵也是有明确含义的(加速矩阵除外),本质上还是要理解算法每一步的目的。
    
    
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int n,m,t,a,b,temp;
    const int md=45989;
    int dis[125][125]={0},tot[2][125]={0},ans[125][125]={0};
    inline int r()
    {
        int jg=0,jk=0;
        jk=getchar()-'0';
        if(jk>=0&&jk<=9)  jg+=jk;
        jk=getchar()-'0';
        while(jk>=0&&jk<=9)
        {
           jg*=10;
           jg+=jk;
           jk=getchar()-'0';
        }
        return jg;
    }
    int h[25],e;
    struct B
    {
         int u,v,ne;
    }bi[125];
    void add(int x,int y)
    {
         bi[e].u=x;
         bi[e].v=y;
         bi[e].ne=h[x];
         h[x]=e++;
    }
    int jg[125][125];
    void jc(int cs1[][125],int cs2[][125])
    {
         memset(jg,0,sizeof(jg));
         for(int i=0;i<temp;i++)
           for(int j=0;j<temp;j++)
             for(int k=0;k<temp;k++)
               jg[i][j]+=(cs1[i][k]*cs2[k][j])%md;
         for(int i=0;i<temp;i++)
           for(int j=0;j<temp;j++)
             cs1[i][j]=jg[i][j]%md;
    }
    void init()
    {
         n=r();
         m=r();
         t=r();
         a=r();
         b=r();
         temp=2*m;
         memset(h,-1,sizeof(h));
         int a1,a2;
         for(int i=0;i<m;i++)
         {
            a1=r();
            a2=r();
            add(a1,a2);
            add(a2,a1);
         }
         for(int i=0;i<n;i++)
          for(int j=h[i];j!=-1;j=bi[j].ne)
            for(int k=h[bi[j].v];k!=-1;k=bi[k].ne)
            {
              if(((k&1)&&k==j+1)||((j&1)&&j==k+1))
                continue;
              dis[j][k]=1;
            }
         for(int i=h[a];i!=-1;i=bi[i].ne)
              tot[0][i]=1;
    }
    int main()
    {
        init();
        for(int i=0;i<temp;i++)
          ans[i][i]=1;
        t--;
        while(t)
        {
           if(t&1) jc(ans,dis);
           t>>=1;
           jc(dis,dis);
        }
        jc(tot,ans);
        int res=0;
        for(int i=h[b];i!=-1;i=bi[i].ne)
        {
          if(i&1)
            res+=tot[0][i-1];
          else
            res+=tot[0][i+1];
        }
        printf("%d",res%md);
        return 0;
    }
    
    
    
     
  • 相关阅读:
    ES6 随记(1)-- let 与 const
    this 机制的四种规则
    BEM(一种 CSS 命名规则)
    WebSocket 的后记
    WebSocket 初体验
    “空”的艺术-当数据为空时显示什么
    前端路由以及浏览器回退,hash & history & location
    体验 WebFont,网页上的艺术字
    dedecms安装全过程(集成环境)
    面向对象(五)
  • 原文地址:https://www.cnblogs.com/moyiii-/p/7182944.html
Copyright © 2011-2022 走看看