码迷,mamicode.com
首页 > 其他好文 > 详细

数列 题解(NOIP模拟T2)

时间:2017-06-29 22:36:23      阅读:297      评论:0      收藏:0      [点我收藏+]

标签:bsp   pac   dash   for   个数   can   最小   事实表   stream   

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置。

 

【题目描述】

a[1]=a[2]=a[3]=1

a[x]=a[x-3]+a[x-1]  (x>3)

a数列的第n项对1000000007(10^9+7)取余的值。

【输入格式】

第一行一个整数T,表示询问个数。

以下T行,每行一个正整数n。

【输出格式】

每行输出一个非负整数表示答案。

【样例输入】

3

6

8

10

【样例输出】

4

9

19

【数据范围】

对于30%的数据 n<=100;

对于60%的数据 n<=2*10^7;

对于100%的数据 T<=100,n<=2*10^9;

 

分析:

数据范围到了二十亿,显然不优化是绝对要TLE的(事实表明暴力只有60分)

由于这是一个加和递推式的形式,所以采用(矩阵)快速幂。

大佬说只要是形似这样的加和的题都可以用矩阵来解。

 

下面是AC代码,注释已经写得很详细了不再多说。矩阵这东西还是应该找人来讲,文字叙述起来太困难。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 
  6 using namespace std;
  7 const int INF = 0x3f3f3f3f;
  8 const int MOD = 1000000007;
  9 
 10 long long s1[10][10],s2[10];
 11 long long tmp[10][10],base[10][10],ans[10][10];
 12 
 13 long long pow(int b)
 14 {
 15     for(int i = 1;i <= 4;i ++)
 16     {
 17         ans[i][i] = 1;
 18         for(int j = 1;j <= 4;j ++)
 19             base[i][j] = s1[i][j] % MOD;
 20     }
 21     //初始化ans为单位矩阵,base为构造矩阵
 22     //以后每次数列+n时只需*base^n
 23     while(b)
 24     {
 25         //b的值不为零,也就是二进制表示中还有1
 26         if(b & 1)
 27         {
 28             for(int i = 1;i <= 4;i ++)
 29                 for(int j = 1;j <= 4;++ j)
 30                     tmp[i][j] = ans[i][j] % MOD;
 31             //b&1判断当前位是否为1,是的话就用tmp存储ans
 32             memset(ans,0,sizeof(ans));
 33             
 34             for(int k = 1;k <= 4;k ++)
 35                 for(int i = 1;i <= 4;i ++)
 36                     for(int j = 1;j <= 4;j ++)
 37                         ans[i][j] += ((tmp[i][k] % MOD) * (base[k][j] % MOD)); 
 38             //用tmp与base做矩阵乘法,求出ans 
 39         }
 40          
 41         for(int i = 1;i <= 4;i ++)
 42              for(int j = 1;j <= 4;j ++)
 43                  tmp[i][j] = base[i][j] % MOD;
 44         //用tmp存储base
 45         
 46         memset(base,0,sizeof(base));
 47         
 48         
 49         for(int k = 1;k <= 4;k ++)
 50             for(int i = 1;i <= 4;i++)
 51                 for(int j = 1;j <= 4;j ++)
 52                     base[i][j] += ((tmp[i][k] % MOD) * (tmp[k][j] % MOD));
 53         //计算出新的base = base * base,实际上是倍增求base 
 54         b >>= 1;        
 55     }
 56     return ((((ans[1][1]%MOD) * (s2[1]%MOD) % MOD) + ((ans[1][2]%MOD) * (s2[2]%MOD) % MOD))%MOD + (((ans[1][3]%MOD) *(s2[3]%MOD)) % MOD + ((ans[1][4]%MOD) * (s2[4]%MOD)) % MOD)%MOD) % MOD;
 57     //返回的是ans与s2的乘积,此时ans为base的n次方,n与题目中的n相统一 
 58 } 
 59 int main()
 60 {
 61     int t,n;
 62     scanf("%d",&t);
 63     while(t)
 64     {
 65         scanf("%d",&n);
 66         if((n == 1) || (n == 2) || (n == 3))
 67         {
 68             printf("1\n");
 69             -- t;
 70             continue;
 71         }
 72         else if(n == 4)
 73         {
 74             printf("2\n");
 75             -- t;
 76             continue;
 77         }
 78         else if(n == 5)
 79         {
 80             printf("3\n");
 81             -- t;
 82             continue;
 83         }
 84         memset(base, 0, sizeof(base));
 85         memset(tmp, 0, sizeof(tmp));
 86         memset(ans, 0, sizeof(ans));
 87         
 88         s2[1] = 3 ;s2[2] = 1;s2[3] = 1;s2[4] = 1;
 89         //手算推出计算an需要an-2、an-3、an-4
 90         //由上面四个量可以推出an+1、an-1、an-2、an-3
 91         s1[1][1] = 1;s1[1][2] = 1;s1[1][3] = 0;s1[1][4] = 0;
 92         s1[2][1] = 0;s1[2][2] = 1;s1[2][3] = 0;s1[2][4] = 1;
 93         s1[3][1] = 0;s1[3][2] = 1;s1[3][3] = 0;s1[3][4] = 0;
 94         s1[4][1] = 0;s1[4][2] = 0;s1[4][3] = 1;s1[4][4] = 0;
 95         long long a = pow(n - 5) % MOD;
 96         printf("%lld\n",a);
 97         -- t;
 98     } 
 99     return 0;
100 }

对于上面88—94行的来历再说一下。

思维过程:

假定我们已知an,需要求an+1,这时我们还需要知道an-2

用an-2可以求得an-1,这时我们还需要知道an-4

用an-4可以求得an-3,an-3又可以求得an-2

将上述整理成矩阵的形式,大概就是这样的:

技术分享

左边是条件,检验可知用左边的四个值可以求得右边的四个值。

而s1矩阵反映的就是从左边的值到右边的值的对应关系,用矩阵乘法计算。

关于矩阵乘法这里不再赘述,前面有一篇博客说过运算法则(尽管说得非常含糊),因为矩阵的东西确实很难用文字表达。。。

至于第95行,为什么pow(n-5),是因为左边的a下标最小是n-4,n-5(其实是n+1-5)与之对应。

数列 题解(NOIP模拟T2)

标签:bsp   pac   dash   for   个数   can   最小   事实表   stream   

原文地址:http://www.cnblogs.com/shingen/p/7096192.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!