HDU3519_Lucky Coins Sequence_推公式_矩阵加速

这道题真好,体现了思想的灵活性。要3个连续状态以上嘛,好,那我就求出

只有1~2个状态的数量,最后总数减去即可。美妙,完结。

/*
*State:    3519    0MS    256K    2354 B    
*题目大意:
*        给定n个硬币,硬币有两种状态0或1,可以翻转,总共有2^n种
*        状态,规定如果有连续3个硬币的状态一样,即是特殊串。要求
*        特殊串的个数。
*解题思路:
*        已知总数目,那么可以用相反的思想求出该串状态不含有3个
*        连续一样的数目,然后用总数去减。
*        长度为 n 的 01 串一共有 2^n 种不同的排列方法 ,
*        设 f(n) 为长度是 n 的不包含连续 3 个或以上相同的 1 或 0 的 01 串 ,
*        则 f(1)=2,f(2)=4,f(3)=6,f(4)=10
*        当 n>4 的时候 , 分情况考虑 :
*            1、   如果是以 00 或者 11 结尾 , 则分别有 f(n-2)/2 种情况 , 
*            加起来就是 f(n-2) 种 .
*            2、   如果是以 01 或者 10 结尾 , 则第 n 个字符要和第 n-1 个
*            字符不一样 , 那么分别有 f(n-1)/2 种 , 加起来就是 f(n-1)
*        则统计起来就是 f(n)=f(n-1)+f(n-2)。之后构造矩阵即可。
*解题感想:
*        这道题目是搜题解的,表示做法其实也就一般,关键看能否想到用反推,还有
*        公式。
*        由于最后有一步减法,由于是模的关系,有可能结果为负,注意模减法的特殊性。
*        由于这个错误贡献了两个wa,还查了半个小时不止。最后还好乱给出测试数据了嘻。
*/
View Code
  1 #include <iostream>
  2 #include <cmath>
  3 #define maxn 3
  4 
  5 using namespace std;
  6 
  7 struct Mat
  8 {
  9     int m, n;
 10     int d[maxn][maxn];
 11     void init(int m, int n) 
 12     {
 13         this->m = m;
 14         this->n = n;
 15         memset(d, 0, sizeof(d));
 16     }
 17     void initE(int size)                              //生成单位阵
 18     {
 19         m = n = size;
 20         for(int i = 0; i < n; i ++)
 21         {
 22             for(int j = 0; j < n; j ++)
 23             {
 24                 d[i][j] = i==j;
 25             }
 26         }
 27     }
 28     Mat operator * (const Mat & mat) const
 29     {
 30         static Mat res;
 31         res.init(m, mat.n);
 32         for(int i = 0; i < res.m; i ++)
 33         {
 34             for(int k = 0; k < n; k ++)
 35             {
 36                 if(d[i][k]==0)    continue;
 37                 for(int j = 0; j < res.n; j ++)
 38                 {
 39                     res.d[i][j] += d[i][k] * mat.d[k][j];
 40                 }
 41             }
 42         }
 43         return res;
 44     }
 45     Mat mul_mod(const Mat & mat, int mod) const
 46     {
 47         static Mat res;
 48         res.init(m, mat.n);
 49         for(int i = 0; i < res.m; i ++)
 50         {
 51             for(int k = 0; k < n; k ++)
 52             {
 53                 if(d[i][k]==0)    continue;
 54                 for(int j = 0; j < res.n; j ++)
 55                 {
 56                     res.d[i][j]=(res.d[i][j]+d[i][k]*mat.d[k][j]) % mod;
 57                 }
 58             }
 59         }
 60         return res;
 61     }
 62     void pow_mod(int k, int mod)                      //this = this^k % mod;
 63     {
 64         static Mat a;
 65         a = *this;
 66         for(this->initE(n); k; k>>=1, a=a.mul_mod(a, mod))
 67             if(k&1)    *this=this->mul_mod(a, mod);
 68     }
 69     void view_arr()
 70     {
 71         for(int i = 0; i < m; i++)
 72         {
 73             for(int j = 0; j < n; j++)
 74                 cout << d[i][j] << " ";
 75             cout << endl;
 76         }
 77     }
 78 };
 79 
 80 int mod_pow(int a,int k,int m) 
 81 {
 82     static int r;
 83     for(r=1;k;k>>=1,a=a*a%m)    if(k&1)    r=r*a%m;
 84     return r;
 85 }
 86 
 87 int main(void)
 88 {
 89 #ifndef ONLINE_JUDGE
 90     freopen("in.txt", "r", stdin);
 91 #endif
 92     int n, mod;
 93     
 94     mod = 10007;
 95 
 96     while(scanf("%d", &n) == 1)
 97     {
 98         Mat a;
 99         a.init(2, 2);
100         a.d[0][0] = a.d[0][1] = a.d[1][0] = 1;
101         a.d[1][1] = 0;
102         if(n == 1 || n == 2)
103         {
104             printf("0\n");
105             continue;
106         }
107         a.pow_mod(n - 2, mod);
108         int tol = mod_pow(2, n, mod);
109         int fn = (a.d[0][0] * 4 + a.d[0][1] * 2) % mod;
110         //cout << "fn: " << fn << endl;
111         //cout << tol << endl;0
112         printf("%d\n", ((tol - fn) % mod + mod) % mod);
113     }
114     return 0;
115 }
原文地址:https://www.cnblogs.com/cchun/p/2619554.html