以后不发题目了。
这道题目嘛,跟
poj2663 poj2411 poj2506
以上三道题思路大致一样,也许以上三道题有的可以找规律或者数学分析什么的,但是这道题目必须用到的是1:状态压缩思想。
2:矩阵乘法。(绝大多数情况下包含快速幂)
建议不会做这道题目的童鞋先去做做poj2411。
(1)基本状态压缩思想我已经在关于poj2411的博客中讲过了,在此不再赘述。
(2)关于矩阵乘法,建议先看看线性代数,需要注意的两点:1:矩阵乘法不满足交换律;2:矩阵乘法满足结合律。
(3)快速幂:求一个数的N次方,通常N非常大,且结果需要对某数取余数。我们可以通过求这个数的1次方,2次方,4次方,8次方。。。。。。最后从幂指数不大于N的数开始加,幂指数小于等于N,则加上这个数,然后N减去这个幂指数,幂指数除以2;不然幂指数重复除以2,直到小于等于N,再重复前面的过程。求解过程中要处处取余。
通过分析状态压缩方程我们可以知道,每一列的2^4=16种状态从上一列的2^4=16种状态转移过来的方式都是相同的,我们可以将这种转化方式转变成一个16*16的由0和1组成的矩阵,在相乘的过程中实现对对应状态的相加。这种方法需要先求出第一列16种状态的可行性,后再右乘这个16×16的矩阵的(n-1)次方,便可以得到第n列的所有状态的方法数,注意要在每一个可能的地方取余数,但为了提高效率也不要全部取余数。
题目很阴,出了个数据:1 1。
小伙伴们被坑倒一片,原因:我们只在计算矩阵乘法时取余数,而没有对最后的结果取余数(因为我们没想到这种数据,一般都是要经过矩阵乘法才能得出结果的),这个数据要求输出的是我们预处理的第一行,直接使AC率降低了数个百分点。
编码过程中要注意的几点:
1:注意&、|、&&、==等符号的优先级顺序,同时记住()的优先级是最高的,这里很容易出错但又不容易发现,不清楚优先级的时候用括号准没错。
2:开数组的时候千万要注意啊啊啊啊啊,宁愿多开几个数也不要认为自己计算的天衣无缝,我就是因为自己太过大意,数组开小了1个数导致交了十几遍全WA,我坑死了我自己。
总的来说,题目还是不难的,注意细节就好,完了~
奥,差点忘了附上代码+_+:
#include<iostream>
#include<cstring> //包含memset
using namespace std;
long a,b,c,d,nn,mm;
struct Matrix
{
long n,m;
long long jz[16][16];
void clear()
{
n=0;m=0;
memset(jz,0,sizeof(jz));
}
friend Matrix operator *(Matrix &t,Matrix &k);
}df,rec[31],sc,aa,bb;
Matrix operator *(Matrix &t,Matrix &k) //重载乘号
{
int i,j,x;
Matrix tmp;
tmp.clear();
tmp.n=t.n;
tmp.m=k.m;
for (i=0;i<t.n;i++)
for (j=0;j<k.m;j++)
{
for (x=0;x<t.m;x++)
tmp.jz[i][j]+=(t.jz[i][x])*(k.jz[x][j]);
tmp.jz[i][j]%=mm;//模模更健康^_^
}
return tmp;
}
long judge(long k) //处理第一行,下面一些语句跟我的poj2411代码一样
{
long i,j=0;
for (i=0;i<4;i++)
{
if ((k&1)&&(j&1)) return 0;
if (!(k&1)) j++;
k>>=1;
}
if (j&1) return 0;
return 1;
}
int main()
{
df.clear();
df.m=16;
df.n=1;
for (a=0;a<16;a++)
df.jz[0][a]=judge(a);
rec[1].m=16;
rec[1].n=16;
for (a=0;a<16;a++)
for (b=0;b<16;b++)
if (!(a&b)&&(df.jz[0][a|b])) rec[1].jz[a][b]=1;//同poj2411代码
for (;;)
{
cin>>nn>>mm;
if (nn==0) break;
sc=df;
nn--;
long now=1,jl=2;
while (jl<=nn)
{
now++;
rec[now]=rec[now-1]*rec[now-1];
jl<<=1;
}
jl>>=1;
while (nn)
{
while (nn<jl)
{
jl>>=1;
now--;
}
sc=sc*rec[now];
nn-=jl;
}//快速幂,注意要右乘
cout<<sc.jz[0][0]%mm<<endl;//注意输出再模一下
}
return 0;
}