码迷,mamicode.com
首页 > 其他好文 > 详细

ZJOI2005沼泽鳄鱼

时间:2018-08-27 21:30:49      阅读:168      评论:0      收藏:0      [点我收藏+]

标签:scan   矩阵   mem   pac   space   不能   a*   存在   mes   

矩阵优化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;
}

ZJOI2005沼泽鳄鱼

标签:scan   矩阵   mem   pac   space   不能   a*   存在   mes   

原文地址:https://www.cnblogs.com/ARTlover/p/9543744.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!