poj3420

3 篇文章 0 订阅

以后不发题目了。

这道题目嘛,跟

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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值