【ch30】摆花

描述 Description

艺术馆门前将摆出许多花,一共有 n 个位置排成一排,每个位置可以摆花也可以不摆花。有些花如果摆在相邻的位置(隔着一个空的位置不算相邻),就不好看了。假定每种花数量无限,求摆花的方案数。

输入格式 InputFormat

输入有 1+m 行,第一行有两个用空格隔开的正整数 n、m,m 表示花的种类数。接下来的 m 行,每行有 m 个字符 1 或 0, 若第 i 行第 j 列为 1,则表示第 i 种花和第 j 种花不能排在相邻的位置,输入保证对称。(提示:同一种花可能不能排在相邻位置)。

输出格式 OutputFormat

输出只有一个整数,为方案数(这个数字可能很大,请输出方案数除以 1000000007 的余数)。

样例输入 SampleInput

5 10
0000000000
0000000000
0000000001
0000000000
0000000000
0000000001
0000000000
0000000000
0000000000
0010010000

样例输出 SampleOutput

142249

数据范围和注释 Hint

20% 的数据,1<n≤5,0<m≤10。

60% 的数据,1<n≤200,0<m≤100。

100% 的数据,1<n≤1000000000,0<m≤100。


CH#30 摆花


代码 Code

假定不摆花也算一种花,构建邻接矩阵当且仅当 i 与 j 种花不冲突时 A(i,j)=1. 矩阵快速幂求 A^n。

(即经典题目:给定一个有向图,问从 A 点恰好走 k 步(允许重复经过边)到达 B 点的方案数 mod p 的值)。

#include <stdio.h>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define mod 1000000007
struct matrix
{
    long long mat[201][201];
};
matrix a,f;
char ch[101];
int i,j,t,n,m,l,r,k,z,y,x;
void TEST()
{
    int i,j,t;
    for (i=0;i<=m;i++) 
    {
        for (j=0;j<=m;j++) cout<<a.mat[i][j]<<" ";
        cout<<endl;
    }
    cout<<endl;
    for (i=0;i<=m;i++) 
    {
        for (j=0;j<=m;j++) cout<<f.mat[i][j]<<" ";
        cout<<endl;
    }
}
matrix matrixmul(matrix a,matrix b)
{
    matrix c;
    int i,j,t,k;
    for (i=0;i<=m;i++) for (j=0;j<=m;j++)
    {
        c.mat[i][j]=0;
        for (k=0;k<=m;k++) c.mat[i][j]+=(a.mat[i][k]*b.mat[k][j])%mod;
        c.mat[i][j]%=mod;
    }
    return c;
}
void qp(int n)
{
    f=a;
    while (n)
    {
        if (n&1) f=matrixmul(f,a);
        n>>=1;
        a=matrixmul(a,a);
    }
}
int main()
{
    memset(a.mat,0,sizeof(a.mat));
    scanf("%d%d",&n,&m);
    for (i=0;i<=m;i++) a.mat[0][i]=a.mat[i][0]=1;
    for (i=1;i<=m;i++)
    {
        scanf("%s",ch);
        for (j=1;j<=m;j++) if (ch[j-1]=='0') a.mat[i][j]=1;
    }
    qp(n);
    printf("%I64d\n",f.mat[0][0]);
    return 0;
}