CH Round #30 摆花[矩阵乘法]
生活随笔
收集整理的這篇文章主要介紹了
CH Round #30 摆花[矩阵乘法]
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
擺花?CH Round #30 - 清明歡樂賽
背景及描述
藝術館門前將擺出許多花,一共有n個位置排成一排,每個位置可以擺花也可以不擺花。有些花如果擺在相鄰的位置(隔著一個空的位置不算相鄰),就不好看了。假定每種花數量無限,求擺花的方案數。
輸入格式
輸入有1+m行,第一行有兩個用空格隔開的正整數n、m,m表示花的種類數。接下來的m行,每行有m個字符1或0,若第i行第j列為1,則表示第i種花和第j種花不能排在相鄰的位置,輸入保證對稱。(提示:同一種花可能不能排在相鄰位置)。
輸出格式
輸出只有一個整數,為方案數(這個數字可能很大,請輸出方案數除以1000000007的余數)。
樣例輸入
2 2 01 10樣例輸出
7樣例說明
七種方案為(空,空)、(空,1)、(1、空)、(2、空)、(空、2)、(1,1)、(2,2)。
數據范圍與約定
- 20%的數據,1<n≤5,0<m≤10。
- 60%的數據,1<n≤200,0<m≤100。
- 100%的數據,1<n≤1000000000,0<m≤100。
?
正解:
這樣來看這個問題,我們先定義一種新的花:不擺花,然后我們把所有種類的
花看成一個點,在不互相沖突的種類之間連一條邊,其中不擺花不和所有花沖突。我們要求 擺到n個位置,實際上可以認為是求這個圖中長度為n的路徑的條數,這樣把問題轉換成了 經典問題,可以運用矩陣乘法求解,得 100 分?
?
關于圖中長度為n路徑計數:
見圖片
?
注意:本題必須邊從0開始
// // main.cpp // ch30B // // Created by Candy on 23/10/2016. // Copyright ? 2016 Candy. All rights reserved. // #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; const int M=105,MOD=1000000007; typedef long long ll; inline int read(){char c=getchar();int x=0,f=1;while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}return x*f; } int n,m; char s[M]; struct mat{ll mt[M][M];mat(){memset(mt,0,sizeof(mt));} }g,im; mat mult(mat &x,mat &y){mat t;for(int i=0;i<=m;i++)for(int k=0;k<=m;k++) if(x.mt[i][k])for(int j=0;j<=m;j++)t.mt[i][j]=(t.mt[i][j]+x.mt[i][k]*y.mt[k][j]%MOD)%MOD;return t; } void dp(){for(int i=0;i<=m;i++)im.mt[i][i]=1;for(;n;n>>=1,g=mult(g,g))if(n&1) im=mult(im,g); } int main(int argc, const char * argv[]){//freopen("harem.in","r",stdin);//freopen("harem.out","w",stdout); n=read();m=read();for(int i=1;i<=m;i++){scanf("%s",s+1);for(int j=1;j<=m;j++) g.mt[i][j]=(s[j]-'0')^1;}for(int i=0;i<=m;i++) g.mt[i][0]=g.mt[0][i]=1;dp();ll ans=0;for(int i=0;i<=m;i++) ans=(ans+im.mt[0][i])%MOD;printf("%lld",ans); }?
總結
以上是生活随笔為你收集整理的CH Round #30 摆花[矩阵乘法]的全部內容,希望文章能夠幫你解決所遇到的問題。