team2012-F3-sol-0010
从 Trac 迁移的文章
这是从旧校内 Wiki 迁移的文章,可能存在一些样式问题,您可以向 memset0 反馈。
原文章内容如下:
{{{
题意:一个k×n的矩形,里面有三种格子并且规定各自的走法,求从最左边任意一行走到最右边任意一行出来的方案数。
解法:由于有许多相同的列相邻,且k很小,可以用矩阵乘法解决,处理出每一种连续的情况下的单列方案数,再快速幂即可。
}}}
{{{
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long LL;
const int MOD = 11142457;
int n, k, m, type[10], plan[10][10];
struct mat
{
LL dt[7][7];
mat()
{
memset(dt, 0, sizeof(dt));
for(int i=0;i<=k;i++)
dt[i][i] = 1;
}
mat operator*(const mat& x)
{
mat res;
memset(&res, 0, sizeof(res));
for(int i=1;i<=k;i++)
for(int j=1;j<=k;j++)
for(int p=1;p<=k;p++)
{
res.dt[i][j] += dt[i][p] * x.dt[p][j];
res.dt[i][j] %= MOD;
}
return res;
}
void operator*=(const mat& x)
{
(*this) = (*this) * x;
}
LL sum()
{
LL s = 0;
for(int i=1;i<=k;i++)
for(int j=1;j<=k;j++)
{
s += dt[i][j];
s %= MOD;
}
return s;
}
};
mat makemat()
{
memset(plan, 0, sizeof(plan));
for(int i=1;i<=k;i++)
{
if(type[i] == 1)
plan[i][i]++;
else if(type[i] == 2)
{
for(int j=i-1;j>=1;j--)
{
if(type[j] == 0)
break;
if(type[j] == 2)
{
plan[i][j]++;
break;
}
}
for(int j=i+1;j<=k;j++)
{
if(type[j] == 0)
break;
if(type[j] == 2)
{
plan[i][j]++;
break;
}
}
}
}
mat ret;
for(int i=1;i<=k;i++)
for(int j=1;j<=k;j++)
ret.dt[i][j] = plan[i][j];
return ret;
}
mat power(mat x, int p)
{
mat ret;
while(p)
{
if(p & 1)
ret *= x;
x *= x;
p >>= 1;
}
return ret;
}
int main()
{
while(~scanf("%d %d %d", &n, &k, &m))
{
mat ans;
for(int i=1;i<=m;i++)
{
int t;
scanf("%d", &t);
for(int j=1;j<=k;j++)
scanf("%d", &type[j]);
ans *= power(makemat(), t);
}
printf("%lld\n", ans.sum());
}
return 0;
}
}}}
题意:一个k×n的矩形,里面有三种格子并且规定各自的走法,求从最左边任意一行走到最右边任意一行出来的方案数。
解法:由于有许多相同的列相邻,且k很小,可以用矩阵乘法解决,处理出每一种连续的情况下的单列方案数,再快速幂即可。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long LL;
const int MOD = 11142457;
int n, k, m, type[10], plan[10][10];
struct mat
{
LL dt[7][7];
mat()
{
memset(dt, 0, sizeof(dt));
for(int i=0;i<=k;i++)
dt[i][i] = 1;
}
mat operator*(const mat& x)
{
mat res;
memset(&res, 0, sizeof(res));
for(int i=1;i<=k;i++)
for(int j=1;j<=k;j++)
for(int p=1;p<=k;p++)
{
res.dt[i][j] += dt[i][p] * x.dt[p][j];
res.dt[i][j] %= MOD;
}
return res;
}
void operator*=(const mat& x)
{
(*this) = (*this) * x;
}
LL sum()
{
LL s = 0;
for(int i=1;i<=k;i++)
for(int j=1;j<=k;j++)
{
s += dt[i][j];
s %= MOD;
}
return s;
}
};
mat makemat()
{
memset(plan, 0, sizeof(plan));
for(int i=1;i<=k;i++)
{
if(type[i] == 1)
plan[i][i]++;
else if(type[i] == 2)
{
for(int j=i-1;j>=1;j--)
{
if(type[j] == 0)
break;
if(type[j] == 2)
{
plan[i][j]++;
break;
}
}
for(int j=i+1;j<=k;j++)
{
if(type[j] == 0)
break;
if(type[j] == 2)
{
plan[i][j]++;
break;
}
}
}
}
mat ret;
for(int i=1;i<=k;i++)
for(int j=1;j<=k;j++)
ret.dt[i][j] = plan[i][j];
return ret;
}
mat power(mat x, int p)
{
mat ret;
while(p)
{
if(p & 1)
ret *= x;
x *= x;
p >>= 1;
}
return ret;
}
int main()
{
while(~scanf("%d %d %d", &n, &k, &m))
{
mat ans;
for(int i=1;i<=m;i++)
{
int t;
scanf("%d", &t);
for(int j=1;j<=k;j++)
scanf("%d", &type[j]);
ans *= power(makemat(), t);
}
printf("%lld\n", ans.sum());
}
return 0;
}