[矩阵乘法优化DP] Topcoder SRM554. TheBrickTowerHardDivOne

32人阅读 评论(0) 收藏 举报
分类:

dp

fi,s 表示第 i 层的状态为 s 的方案数

转移是一个矩乘的形式

用矩乘快速幂优化

#include <cstdio>
#include <iostream>
#include <algorithm>

using namespace std;

const int P=1234567891;

typedef int mat[130][130];
typedef long long ll;

int cb[20010][5],num[20010],t,vis[20010],vst[10];
int a[10];

inline void judge(){
  vst[1]=vst[2]=vst[3]=vst[4]=0; int ct=0;
  for(int i=1;i<=4;i++){
    if(!vst[a[i]]) vst[a[i]]=++ct;
    a[i]=vst[a[i]];
  }
  int val=0;
  for(int i=1;i<=4;i++) val=val*5+a[i];
  if(!vis[val]){
    num[t]=ct;
    for(int i=1;i<=4;i++)
      cb[t][i]=a[i];
    t++; vis[val]=1; 
  }
}

int n;
mat trans;
int c,k,h,cur,matc[10],fac[20010],inv[20010],cao[20010];

void dfs(int x){
  if(x>4) return judge();
  for(int i=1;i<=4;i++){
    a[x]=i; dfs(x+1);
  }
}

inline int C(int x,int y){
  if(x<y) return 0;
  return 1LL*fac[x]*inv[x-y]%P;
}

vector<pair<int,int> > cc;

inline void calc(int S,int T,int nb,int tot){
  for(int i=1;i<=4;i++){
    if(matc[cb[T][i]]==cb[S][i]) nb--;
  }
  if(!nb) cur=((ll)cur+tot)%P;
}

void pfs(int x,int S,int T,int nb,int tot){
  if(x>num[T]) return calc(S,T,nb,tot);
  for(int i=0;i<cc.size();i++){
    matc[x]=cc[i].first; cao[i]++;
    pfs(x+1,S,T,nb,1LL*tot*(cc[i].second-cao[i]+1)%P);
    cao[i]--;
  }
}

int calc(int x,int y){
  if(y==n) return 1;
  if(x==n) return 0;
  int sx=x/k,sy=y/k,cnt=0;
  cnt+=(cb[sy][1]==cb[sy][2])+(cb[sy][3]==cb[sy][4]);
  cnt+=(cb[sy][1]==cb[sy][3])+(cb[sy][2]==cb[sy][4]);
  if(x%k-cnt<y%k) return 0;
  cur=0; cc.clear();
  for(int i=1;i<=4;i++) cc.push_back(make_pair(cb[sx][i],1));
  sort(cc.begin(),cc.end()); cc.erase(unique(cc.begin(),cc.end()),cc.end());
  if(c-cc.size()) cc.push_back(make_pair(5,c-cc.size()));
  for(int i=0;i<cc.size();i++) cao[i]=0;
  cur=0; pfs(1,x/k,y/k,x%k-cnt-y%k,1); return cur;
}

inline void Pre(){
  dfs(1);
  fac[0]=1; for(int i=1;i<=5000;i++) fac[i]=1LL*fac[i-1]*i%P;
  inv[1]=1; for(int i=2;i<=5000;i++) inv[i]=1LL*(P-P/i)*inv[P%i]%P;
  inv[0]=1; for(int i=1;i<=5000;i++) inv[i]=1LL*inv[i]*inv[i-1]%P;
}

mat res,init;

inline int count(int x){
  return (cb[x][1]==cb[x][2])+(cb[x][3]==cb[x][4])+(cb[x][1]==cb[x][3])+(cb[x][2]==cb[x][4]);
}

inline void mul(mat a,mat b,mat &c){
  static mat tmp;
  for(int i=0;i<=n;i++)
    for(int j=0;j<=n;j++) tmp[i][j]=0;
  for(int i=0;i<=n;i++)
    for(int j=0;j<=n;j++)
      for(int k=0;k<=n;k++)
    tmp[i][j]=(tmp[i][j]+1LL*a[i][k]*b[k][j])%P;
  for(int i=0;i<=n;i++)
    for(int j=0;j<=n;j++) c[i][j]=tmp[i][j];
}

inline void add(mat a,mat b,mat &c){
  static mat tmp;
  for(int i=0;i<=n;i++)
    for(int j=0;j<=n;j++) tmp[i][j]=0;
  for(int i=0;i<=n;i++)
    for(int j=0;j<=n;j++)
      tmp[i][j]=((ll)a[i][j]+b[i][j])%P;
  for(int i=0;i<=n;i++)
    for(int j=0;j<=n;j++) c[i][j]=tmp[i][j];
}

class TheBrickTowerHardDivOne{
public:
  int find(int Cc, int K, ll H){
    c=Cc; k=K+1; h=H;
    Pre(); n=t*(K+1);
    for(int i=0;i<=n;i++)
      for(int j=0;j<=n;j++)
    trans[i][j]=calc(i,j);
    for(int i=0;i<t;i++)
      if(count(i)<=K){
    //cerr<<'\t'<<i<<' '<<K-count(i)<<endl;
    init[0][i*(K+1)+K-count(i)]=C(c,num[i]);
    //init[1][n]=((ll)init[1][n]+C(c,num[i]))%P;
      }
    //for(int i=1;i<=H;i++)
    //  mul(init,trans,init);
    for(int i=0;i<=n;i++) res[i][i]=1;
    for(;H;H>>=1,mul(trans,trans,trans)) if(H&1) mul(trans,res,res);
    mul(init,res,res);
    return res[0][n];
  }
}Main;

int main(){
  cout<<Main.find(4,7,47);
  for(;;);
}
查看评论

矩阵乘法优化DP

矩阵乘法优化DP 在许多的DP题目中,转移方程本身不难推,但是需要循环的次数巨大。这时候可以利用矩阵乘法将时间复杂度从O(n) 优化到 O(log n)。这里只用十分简单的一维DP做例子。如何乘在矩...
  • u011056504
  • u011056504
  • 2016-06-04 17:03:35
  • 1897

矩阵乘法的常数优化

矩阵乘法的常数优化 philipsweng 虽然说作为键盘科学家,我们更应该关心程序的时间复杂度。但是一个写的不好的程序可能在实际运行会跟时间复杂度更差的程...
  • PhilipsWeng
  • PhilipsWeng
  • 2015-04-16 10:03:44
  • 1185

矩阵乘法的优化

矩阵乘法的优化 分类: 代码优化2013-06-01 08:41 533人阅读 评论(1) 收藏 举报 题目地址:http://www.51nod.com/onlineJudge/...
  • u010304217
  • u010304217
  • 2014-08-06 09:42:13
  • 564

HDU 5318 (dp+矩阵快速幂优化)

The Goddess Of The Moon Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java...
  • wust_zzwh
  • wust_zzwh
  • 2015-07-29 16:20:02
  • 645

[dp优化]个人对dp优化的理解

动态规划优化 矩阵乘法 单调队列 斜率优化 决策单调性 四边形不等式
  • hbhcy98
  • hbhcy98
  • 2016-02-05 13:34:25
  • 2317

【Contra】 矩阵乘法优化 dp

偶然间,chnlich发现了他小时候玩过的一个游戏“魂斗罗”,于是决定怀旧。但是这是一个奇怪的魂斗罗MOD。有N个关卡,初始有Q条命。每通过一个关卡,会得到u分和1条命,生命上限为Q。其中u=min(...
  • Owen_hzt
  • Owen_hzt
  • 2014-12-11 16:31:17
  • 1046

BZOJ 1875 SDOI 2009 HH去散步 矩阵乘法优化DP

题目大意:给出一张无向图,求从A到B走k步(不能走回头路)的方案数。(k 思路:看到k的范围就知道是矩阵乘法了。关键是不能走回头路怎么构造。正常的方法构造点的转移不能避免这个问题,就用边来...
  • jiangyuze831
  • jiangyuze831
  • 2014-12-13 11:52:56
  • 933

Topcoder SRM 701 Div2

Topcoder SRM 701 Div2话说终于又回到了Div1的坑里.上一把掉得太惨了啊…黄名掉到绿名…SquareFreeString这题还是很简单的吧(zqh被&和==的优先级坑了呢,重回灰名...
  • Spylft
  • Spylft
  • 2016-10-27 18:49:04
  • 466

关于矩阵优化的DP总结

在很多题目总我们列出了dp的转移状态方程,但是某一维的之很大,用滚动数组会超时,这是我们就将借矩阵来进行优化,利用矩阵优化的关键就是构造A矩阵,自己期初不能很轻易的列出矩阵,通过一些列的研究,自己总结...
  • tjqACM
  • tjqACM
  • 2015-04-24 08:36:43
  • 304

Topcoder好题推荐 ( 持续更新中)

推荐的好题不一定是难题,但往往带有那么一点代表性。凡是由别人推荐的题目,偶会加上推荐人ID和blog地址。偶自己推荐的题目,偶会尽量推荐一份简洁的代码。当天推荐的题会以红色标记。 Single ...
  • piaocoder
  • piaocoder
  • 2016-04-01 17:06:24
  • 1007
    个人资料
    持之以恒
    等级:
    访问量: 10万+
    积分: 5255
    排名: 6489
    文章分类
    最新评论