zoukankan      html  css  js  c++  java
  • ZJOI2005沼泽鳄鱼

    矩阵优化dp

    ** 注意:矩阵乘法没有交换律 **

    思路:类比P2151hh去散步

    代码特点在一维的答案矩阵

    1.矩阵优化两点间方案数不必赘述

    2.注意2,3,4可以办到以他们的lcm为周期,正是因为如此我们可以矩阵加速(这样我们就可以化动为静,矩阵乘法了)

    3.一维初始矩阵(一维邻接矩阵+第二个矩阵取交集)注意当前鳄鱼的位置与我们下一次走并无关,他们正好搓了一位,要小心

    4.再次强调:矩阵乘法没有交换律:因此,我们在构造转移矩阵时要从2开始到12,再乘1(这里指的是矩阵)

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int n,m,S,E,k,t,mod=10000;
    int record[20][60],Map[60][60];
    struct M{
      int m[60][60];
      M(){
        memset(m,0,sizeof(m));
      }
      M operator *(const M &a)const {//重载定义矩阵乘法
        M ret;
        for(int i=1;i<=n;++i)
          for(int j=1;j<=n;++j)
            for(int k=1;k<=n;++k)
              ret.m[i][j]=(ret.m[i][j]+m[i][k]%mod*a.m[k][j]%mod)%mod;
        return ret;
      }
    }c[20],e,A;
    inline void build(){//构造转移矩阵
      for(int i=1;i<=n;++i)e.m[i][i]=1;
       for(int i=1;i<=12;++i){
          for(int j=1;j<=n;++j){
              for(int k=1;k<=n;++k){           
                if(Map[j][k]&&(!record[i][j]))c[i].m[k][j]=1;
              }
          }
       }
       for(int i=2;i<=12;i++)e=e*c[i];//矩乘没有交换律
       e=e*c[1];//因为我们的第二个矩阵跟第一步有关,所以先乘2矩阵
    }
    inline void power(M &a,M &b,int k){
      while(k){
        if(k&1)a=a*b;
        b=b*b;
        k>>=1;
      }
    }//矩阵快速幂
    inline void solve(){//极其繁琐需要头脑冷静
      if(k==1){printf("%d",Map[S][E]);return ;}
      for(int i=1;i<=n;++i)if(Map[S][i]&&c[2].m[S][i])A.m[S][i]=1;//先跟第二矩阵取交集,表示走第一步--此处表示构造初始矩阵
      if(k<=12)for(int i=3;i<=k+1;++i)A=A*c[i%12];//此处分类讨论
      else {//因为初始矩阵的存在,我们已经走了一步
        for(int i=3;i<=12;++i)A=A*c[i];//所以在这里我们先暴力走一遍
        A=A*c[1];//注意不能交换律
        power(A,e,(k/12)-1);//先乘了一遍所以-1
        for(int i=2;i<=(k-12)%12+1;++i)A=A*c[i];//最后再o再
      }
      printf("%d",A.m[S][E]);
    }
    
    int main(){
       scanf("%d%d%d%d%d",&n,&m,&S,&E,&k);
       S++,E++;//加1比较顺我的思路,下面的加1同
       for(int i=1;i<=m;++i){
        int x,y;
        scanf("%d%d",&x,&y);
        ++x,++y;
        Map[x][y]=1;
        Map[y][x]=1;
       }
       scanf("%d",&t);
       for(int i=1;i<=t;++i){
         int num;
         scanf("%d",&num);
         for(int j=1;j<=num;++j){
          int x;
          scanf("%d",&x);
          int k=j;
          x++;
          while(k<=12){
            record[k][x]=1;
                k+=num;
          }//12一循环
         }
       }
       build();
       solve();
       return 0;
    }
    
  • 相关阅读:
    Mybatis多层嵌套查询
    UUID 唯一性实现原理
    oracle 多实例启动
    orcal启动多实例是报 ORA-00845: MEMORY_TARGET not supported onthis system
    java调用quartz 2.2.2方法总结。
    mybatis中like的使用(模糊查询)
    Orcal数据库实现主键ID自增
    spring cloud分布式关于熔断器
    spring cloud分布式健康检查
    spring cloud分布式整合zipkin的链路跟踪
  • 原文地址:https://www.cnblogs.com/ARTlover/p/9543744.html
Copyright © 2011-2022 走看看