HDOJ 4602 - Partition 打表找公式,然后矩阵乘法解决..


     这种题一看就想跪...数学思维不行..推不出什么东西..索性先把打表出来看看.. 

HDOJ 4602 - Partition 打表找公式,然后矩阵乘法解决.._第1张图片

   规律有了...实际上要求的是这么一串数列(1,2,5,12,28,64,144,320,704,1536....)的某一项...而这个数列满足F[ i ] = F[ i-1 ] *2 + 2^(i-2) ...

   构造矩阵:   M =     2   0   答案为 [ 5,2 ] * M^(n-k-2) 的[0][0]...

                                2   2  


Program:

#include<iostream>
#include<stack>
#include<queue>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<cmath>
#define ll long long
#define oo 1000000007
#define MAXN 100010
using namespace std;
struct Matrix
{
      ll a[2][2];
};
Matrix MatrixMul(Matrix a,Matrix b)
{
      int i,j,k;
      Matrix h;
      memset(h.a,0,sizeof(h.a));
      for (k=0;k<2;k++)
         for (i=0;i<2;i++)
            for (j=0;j<2;j++)
               h.a[i][j]=(h.a[i][j]+(a.a[i][k]*b.a[k][j])%oo)%oo;
      return h;         
}
Matrix GetMarix(Matrix a,int n)
{
      Matrix h,p;
      int i;
      h.a[0][0]=h.a[1][1]=1,h.a[0][1]=h.a[1][0]=0;
      p=a;
      for (i=0;i<=30;i++)
      {
            if (n & (1<<i)) h=MatrixMul(h,p);
            p=MatrixMul(p,p);
      }
      return h;
}
int main()
{   
      int Case,n,k;
      ll ans;
      Matrix h; 
      scanf("%d",&Case);
      while (Case--)
      {  
             scanf("%d%d",&n,&k);
             if (k>n)   { printf("0\n");  goto A; }
             if (k==n)  { printf("1\n");  goto A; }
             if (k==n-1){ printf("2\n");  goto A; } 
             h.a[0][0]=2,h.a[0][1]=0,h.a[1][0]=2,h.a[1][1]=2;
             h=GetMarix(h,n-k-2);
             ans=((5*h.a[0][0])%oo+h.a[1][0])%oo;
             printf("%I64d\n",ans);
             A: ;
      }
      return 0;
} 


你可能感兴趣的:(HDOJ 4602 - Partition 打表找公式,然后矩阵乘法解决..)