AcWing 1217. 垒骰子
考察:线性dp+矩阵快速幂
思路:
将限制条件作为动态规划的维度,某两个数字不能紧连,这只与骰子的上面或下面有关,可以用f[i][j] 表示第i个骰子,其最上面是j.f[i][j] = f[i-1][k]*4,j的对面与k不互斥,骰子可以绕中心旋转.如果互斥常数就是0.时间复杂度n*6*6
因为n过大,所以需要优化算法.这里涉及到矩阵快速幂.因为f[i][j] += f[i-1][k]*4,(1<=j<=6&&1<=k<=6)是相乘累加,可以考虑设置6维向量.f[i][j] 表示 {f[i][1],f[i][2]..f[i][6]}.a数组则是系数数组,不是0就是4.
1 #include <iostream> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 typedef long long LL; 6 const int N = 7,Mod = 1e9+7; 7 int re[N],mp[N][N],ans; 8 void mul(int f[],int a[][N]) 9 { 10 int res[N]; 11 memset(res,0,sizeof res); 12 for(int i=1;i<=6;i++) 13 for(int j=1;j<=6;j++) 14 res[i] = (res[i]+(LL)f[j]*a[j][i])%Mod; 15 memcpy(f,res,sizeof res); 16 } 17 void mulself(int a[][N]) 18 { 19 int res[N][N]; 20 memset(res,0,sizeof res); 21 for(int i=1;i<=6;i++) 22 for(int j=1;j<=6;j++) 23 for(int k=1;k<=6;k++) 24 res[i][j] = (res[i][j]+(LL)a[i][k]*a[k][j])%Mod; 25 memcpy(a,res,sizeof res); 26 } 27 int main() 28 { 29 for(int i=1;i<=3;i++) re[i] = i+3,re[i+3] = i; 30 for(int i=1;i<=6;i++) 31 for(int j=1;j<=6;j++) mp[i][j] = 4; 32 int n,m; 33 scanf("%d%d",&n,&m) ; 34 while(m--) 35 { 36 int x,y; scanf("%d%d",&x,&y); 37 mp[x][re[y]] = 0,mp[y][re[x]] = 0; 38 } 39 int f[N] = {0,4,4,4,4,4,4}; 40 n--; 41 while(n) 42 { 43 if(n&1) mul(f,mp); 44 mulself(mp); 45 n>>=1; 46 } 47 for(int i=1;i<=6;i++) ans = (ans+f[i])%Mod; 48 printf("%d\n",ans); 49 return 0; 50 }