Codeforces Gym 100199E
题目链接:http://acm.hust.edu.cn/vjudge/problem/109646
题目大意:
给出一个m*n的矩阵,要求每格用黑色或白色填充,且任意一个2x2的部分不能同色,求有多少种填充方案。 1<=n<=10^100,1<=m<=5
分析:
注意到m只有5,而相比之下n的范围却大的惊人,因此我们可以枚举每一列的状态(最多32种),枚举得出哪两列可以相邻,建出一个初始图。
不难得出DP转移方程:设F[i][s]为在第i列为状态S的情况下有多少种填法,则F[i][s]=sum(F[i-1][K]) (K为可以与S相邻的状态)
但这样做时间是O(n)的,难以承受。
因此我们可以用递推数列中常用的优化方法:矩阵快速幂
如图所示,将F序列变换到G序列,需要乘上一个系数矩阵。
如果需要多次变换,那么我们只要将矩阵自乘就可以了。
而矩阵的幂是O(m^3logn)的,在这里因为矩阵很小,m可忽略。于是我们就将递推做到了对数级别的时间。
这种方法适用面很广,基本不涉及最优决策的DP都可以用这种方式优化,比如求斐波拉契数列的第n项。而且矩阵也比较好构造,代码复杂度也不高。
关于n高精度问题,可以用十进制快速幂解决(感谢cx大爷提供方法)
代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#define rep(i,x,y) for (int i=x;i<=y;i++)
#define dep(i,y,x) for (int i=y;i>=x;i--)
#define bit(x,d) (((x&(1<<d))==0)?0:1)
using namespace std;
const int maxn=100+23;
int ans,m,p,len,Mba[maxn][maxn],M[maxn][maxn];
char n[maxn];
void init() //初始构造出基本矩阵
{
memset(Mba,0,sizeof(Mba));
rep(i,0,(1<<m)-1)
rep(j,0,(1<<m)-1)
{
bool mark=1;
rep(k,1,m-1)
if ((bit(i,k)==bit(i,k-1))&&(bit(j,k)==bit(j,k-1))&&(bit(i,k)==bit(j,k))) {mark=0;break;}
if (mark) Mba[i][j]=1;
}
}
void mul(int M[maxn][maxn],int a[maxn][maxn],int b[maxn][maxn]) //矩阵乘法
{
int temp[maxn][maxn];
rep(i,0,(1<<m)-1)
rep(j,0,(1<<m)-1)
{
temp[i][j]=0;
rep(k,0,(1<<m)-1) temp[i][j]+=a[i][k]*b[k][j];
temp[i][j]%=p;
}
rep(i,0,(1<<m)-1) rep(j,0,(1<<m)-1) M[i][j]=temp[i][j];
}
void cmp(int a[maxn][maxn],int M[maxn][maxn])
{
rep(i,0,(1<<m)-1) rep(j,0,(1<<m)-1) M[i][j]=a[i][j];
}
void get_pow(int M[maxn][maxn],int k) //快速幂
{
if (k==0)
{
memset(M,0,sizeof(M));
rep(i,0,(1<<m)-1) M[i][i]=1;
}
else
{
int p[maxn][maxn];get_pow(p,k-1),cmp(p,M);
rep(i,1,9) mul(M,M,p);
rep(i,1,n[k]-'0') mul(M,Mba,M);
}
}
int main()
{
freopen("nice.in","r",stdin);
freopen("nice.out","w",stdout);
scanf("%s%d%d",n+1,&m,&p);
len=strlen(n+1);
n[len]--;
dep(i,len,1)
if (n[i]<'0')
{
n[i-1]--;
n[i]+=10;
}
if (n[1]=='0') {rep(i,1,len) n[i]=n[i+1];len--;}
init();
get_pow(M,len);
ans=0;
rep(i,0,(1<<m)-1) rep(j,0,(1<<m)-1) ans+=M[i][j];
printf("%d\n",ans%p);
return 0;
}

浙公网安备 33010602011771号