Problem 3 czy的后宫(harem.cpp/c/pas)
【题目描述】
czy要妥善安排他的后宫,他想在机房摆一群妹子,一共有n个位置排成一排,每个位置可以摆妹子也可以不摆妹子。有些类型妹子如果摆在相邻的位置(隔着一个空的位置不算相邻),就不好看了。假定每种妹子数量无限,求摆妹子的方案数。
【输入格式】
输入有m+1行,第一行有两个用空格隔开的正整数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。
【题解】
题目很有意思。。
这么晚了不详细写了,反正就是矩阵乘法加速递推
可以把不摆妹子的情况看成一种特殊的妹子,叫做“空妹子”
f[i][j]表示考虑了前i个妹子,最后一个妹子是j,那么f[i][j]=∑f[i-1][each k 满足map[k][j]==0],我们把map里的值全都取反(0变1,1变0),那么f[i][j]=∑f[i-1][each k 满足map[k][j]==0]。
把i这维去掉比较好看f[j]=∑f[k] (map[k][j]==1)
也就是f[j]=∑f[k]*map[k][j]
构建矩阵{f[1],f[2],...,f[m]}
把它乘上map正好得到下一个{f[1],f[2],...,f[m]}
矩阵乘法快速幂,时间复杂度O(lb n * M^3)
代码
#include
#include
#define ll long long
#define p 1000000007
#define maxm 110
using namespace std;
ll n, m;
struct matrix
{
int m[maxm][maxm], t;
ll r ,c;
matrix(){memset(m,0,sizeof(m));}
matrix(ll x, ll y){r=x;c=y;memset(m,0,sizeof(m));}
matrix operator*(matrix t)
{
matrix ans(r,t.c);
ll i, j, k;
for(i=1;i<=r;i++)
for(j=1;j<=t.c;j++)
for(k=1;k<=c;k++)
ans.m[i][j]=int(( (ll)ans.m[i][j] + (ll)m[i][k]*(ll)t.m[k][j] ) %p);
return ans;
}
void show()
{
ll i, j;
for(i=1;i<=r;i++)
{
for(j=1;j<=c;j++)printf("%d ",m[i][j]);printf("\n");
}
}
};
matrix pow(matrix a, ll b)
{
matrix t, ans(a.r,a.r);
ll i, j;
for(i=1;i<=ans.r;i++)ans.m[i][i]=1;
for(t=a;b;b>>=1,t=t*t)if(b&1)ans=ans*t;
return ans;
}
int main()
{
freopen("harem.in","r",stdin);
freopen("harem.out","w",stdout);
ll i, j, ans;
char s[150];
scanf("%I64d%I64d",&n,&m);
matrix a(1,m+1), t(m+1,m+1);
for(i=1;i<=m;i++)
{
scanf("%s",s+1);
for(j=1;j<=m;j++)t.m[i][j]=!(s[j]-48);
t.m[i][m+1]=1;
}
for(i=1;i<=m+1;i++)t.m[m+1][i]=1;
m++;
for(i=1;i<=m;i++)a.m[1][i]=1;
t=pow(t,n-1);
a=a*t;
for(i=1,ans=0;i<=m;i++)ans=(ans+a.m[1][i])%p;
printf("%I64d\n",ans);
return 0;
}