线性规律题目的求解与心得

比赛的时候规律题是很常见的事情 ,所以这里做下总结。

解题分几个步骤;

1 : 首先规律题的数据规模是大的 , 可以说如果结果是数字样的话,而且数据大很有可能的规律;

2 : 暴力打表找到前面10位数字;

2(1)  :  如果足够强大可以根据某种灵性的解法得出答案(我是不够灵的。。)

3 :如果足够强大可以暴力推出公式;

3(1) : 运用技巧性得出结果

4:运用矩阵快速幂

例如: HDU 6185

用没有数量限制2×1和1×2的矩形去铺一块4×n的矩形,有多少种方法

n最大1e^18

  1: 打出暴力程序(参考状态压缩DP瓷砖覆盖):

*/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <queue>
#include <algorithm>
#include <map>
#include <cmath>
#include <iomanip>
#define INF 99999999
typedef long long LL;
using namespace std;
 
const int MAX=(1<<11)+10;
int n,m;
LL temp[MAX],dp[MAX],bin[15];
bool mark[MAX];
 
bool check(int i){
    while(i){
        if(i&1){
            i>>=1;
            if(!(i&1))return false;//第j列是1则第j+1列必须是1 
            i>>=1;//继续判断下一列 
        }else i>>=1;//继续判断下一列 
    }
    return true;
}
 
void Init(){
    memset(mark,false,sizeof mark);
    memset(temp,0,sizeof temp);
    for(int i=0;i<bin[m];++i){//初始化第一行和可以到达什么状态 
        if(check(i))temp[i]=1,mark[i]=true;
    }
}
 
void DP(){
    for(int k=2;k<=n;++k){
        for(int i=0;i<bin[m];++i)dp[i]=0;
        for(int i=0;i<bin[m];++i){
            for(int j=0;j<bin[m];++j){
                if((i|j) != bin[m]-1)continue;//每一位或之后必须每一位是1(综合前面3种情况和分析可知)
                if(!mark[i&j])continue;//由初始化和前面分析三种情况分析可知i&j必须得到和初始化可以到达的状态一样才行
                dp[i]+=temp[j];//i可以从j到达,则增加j的方案数 
            }
        }
        for(int i=0;i<bin[m];++i)temp[i]=dp[i];
    }
}
 
int main(){
    bin[0]=1;
    for(int i=1;i<12;++i)bin[i]=2*bin[i-1];
    while(~scanf("%d%d",&n,&m),n+m){
        if(n<m)swap(n,m);//始终保持m<n,提高效率 
        Init();
        DP();
        printf("%lld
",temp[bin[m]-1]);//输出最后一行到达时的状态必须全部是1 
    }
    return 0;
}
View Code

1 1 
2 5 
3 11 
4 36 
5 95 
6 281 
7 781 
8 2245 
9 6336 
10 18061 

然后就可以得出前面的10项数字 , 然后

2 : 

(1)暴力推出线性公式 ;

(2) 根据这十个数利用高斯消元,先假设是f(n)=f(n-1)*a+f(n-2)*b    (学到了)
         如果高斯消元得到的结果不是整数接着试 
        最终f(n)=f(n-1)*a+f(n-2)*b+f(n-3)*c+f(n-4)*d

//f(n)=f(n-1)*a+f(n-2)*b+f(n-3)*c+f(n-4)*d情况下的高斯消元
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
const int maxn=105;
typedef double Matrix[maxn][maxn];
Matrix A,S;
//n是方程的个数
void gauss(Matrix A,int n)
{
    int i,j,k,r;
    for(int i=0; i<n; i++)
    {
        r=i;
        for( j=i+1; j<n; j++)
            if(fabs(A[j][i])>fabs(A[r][i]))r=j;
        if(r!=i)
            for(j=0; j<=n; j++)swap(A[r][j],A[i][j]);
        for(k=i+1; k<n; k++)
        {
            double f=A[k][i]/A[i][i];
            for(j=i; j<=n; j++)
                A[k][j]-=f*A[i][j];
        }
    }
    for(i=n-1; i>=0; i--)
    {
        for(j=i+1; j<n; j++)
            A[i][n]-=A[j][n]*A[i][j];
        A[i][n]/=A[i][i];
    }
}
int main()
{

    memset(A,0,sizeof(A));
    A[0][0]=95,A[0][1]=36,A[0][2]=11,A[0][3]=5,A[1][0]=6336,A[1][1]=2245,A[1][2]=781;
    A[1][3]=281,A[2][0]=781,A[2][1]=281,A[2][2]=95,A[2][3]=36,A[3][0]=2245,A[3][1]=781;
    A[3][2]=281,A[3][3]=95,A[0][4]=281,A[1][4]=18061,A[2][4]=2245,A[3][4]=6336;
    gauss(A,4);
    for(int i=0; i<4; i++)
    {
        printf("%8.2f
",A[i][4]);
    }
    return 0;
}
View Code

运行得到结果 
1.00 
5.00 
1.00 
-1.00 
所以f(n)=f(n-1)+f(n-2)*5+f(n-3)-f(n-4)

然后根据递推公式用矩阵快速幂解决

值得注意的是由于矩阵系数有负数,在做矩阵相乘时注意+mod再取膜

#include <cstdio>
#include <vector>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
#define mst(a,b) memset((a),(b),sizeof(a))
#define rush() int T,scanf("%d",&T),while(T--)

typedef long long ll;
const int maxn = 4;
const ll mod = 1000000007;
const int INF = 0x3f3f3f3f;

struct Matrix
{
    ll temp[maxn][maxn];
} a;

void init()
{
    for(int i=0;i<maxn;i++)
    for(int j=0;j<maxn;j++)
    {
        a.temp[i][j]=0;
    }
    a.temp[0][0]=a.temp[0][2]=1;
    a.temp[0][1]=5;
    a.temp[0][3]=-1;
    a.temp[1][0]=a.temp[2][1]=a.temp[3][2]=1;
}
Matrix mul(Matrix a,Matrix b)
{
    Matrix ans;
    for (int i=0; i<maxn; i++)
        for (int j=0; j<maxn; j++)
        {
            ans.temp[i][j]=0;
            for (int k=0; k<maxn; k++)
            {
                ans.temp[i][j]+=(a.temp[i][k]*b.temp[k][j]+mod)%mod;  //特别注意
                ans.temp[i][j]%=mod;
            }
        }
    return ans;
}

void fun(Matrix ans,ll k)
{
    for(int i=0; i<maxn; i++)
        for(int j=0; j<maxn; j++)
            a.temp[i][j]=(i==j);
    while(k)
    {
        if(k%2)
            a=mul(a,ans);
        ans=mul(ans,ans);
        k/=2;
    }
}

int main()
{
    Matrix t;
    ll n;
    for(int i=0;i<maxn;i++)
    for(int j=0;j<maxn;j++)
    {
        t.temp[i][j]=0;
    }
    t.temp[0][0]=36;
    t.temp[1][0]=11;
    t.temp[2][0]=5;
    t.temp[3][0]=1;
    while(~scanf("%I64d",&n))
    {
        init();
        if(n<=4)
        {
            printf("%I64d
",t.temp[4-n][0]);
            continue;
        }
        fun(a,n-4);
        a=mul(a,t);
        ll ans=a.temp[0][0]%mod;
        printf("%I64d
",ans);
    }
    return 0;
}
View Code

(3)灵性的解法:https://blog.csdn.net/elbadaernu/article/details/77825979

3:

上面的步骤都是为了得出:f(n)=f(n-1)+f(n-2)*5+f(n-3)-f(n-4)

知道了这个线性的方程后 , 写出矩阵快速幂

  | 1 5 1 -1 |       | F[n-1] |           | F[n]  |

  | 1 0 0 0 |    *   | F[n-2] |    =     | F[n-1] |

  | 0 1 0 0 |        |F[n-3] |             | F[n-2] |

  | 0 0 1 0 |        | F[n-4]|            | F[n-3] |

4:修改快速迷模板:

然后AC:

#include <cstdio>
#include <vector>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
#define mst(a,b) memset((a),(b),sizeof(a))
#define rush() int T,scanf("%d",&T),while(T--)

typedef long long ll;
const int maxn = 4;
const ll mod = 1000000007;
const int INF = 0x3f3f3f3f;

struct Matrix
{
    ll temp[maxn][maxn];
} a;

void init()
{
    for(int i=0;i<maxn;i++)
    for(int j=0;j<maxn;j++)
    {
        a.temp[i][j]=0;
    }
    a.temp[0][0]=a.temp[0][2]=1;
    a.temp[0][1]=5;
    a.temp[0][3]=-1;
    a.temp[1][0]=a.temp[2][1]=a.temp[3][2]=1;
}
Matrix mul(Matrix a,Matrix b)
{
    Matrix ans;
    for (int i=0; i<maxn; i++)
        for (int j=0; j<maxn; j++)
        {
            ans.temp[i][j]=0;
            for (int k=0; k<maxn; k++)
            {
                ans.temp[i][j]+=(a.temp[i][k]*b.temp[k][j]+mod)%mod;  //特别注意
                ans.temp[i][j]%=mod;
            }
        }
    return ans;
}

void fun(Matrix ans,ll k)
{
    for(int i=0; i<maxn; i++)
        for(int j=0; j<maxn; j++)
            a.temp[i][j]=(i==j);
    while(k)
    {
        if(k%2)
            a=mul(a,ans);
        ans=mul(ans,ans);
        k/=2;
    }
}

int main()
{
    Matrix t;
    ll n;
    for(int i=0;i<maxn;i++)
    for(int j=0;j<maxn;j++)
    {
        t.temp[i][j]=0;
    }
    t.temp[0][0]=36;
    t.temp[1][0]=11;
    t.temp[2][0]=5;
    t.temp[3][0]=1;
    while(~scanf("%I64d",&n))
    {
        init();
        if(n<=4)
        {
            printf("%I64d
",t.temp[4-n][0]);
            continue;
        }
        fun(a,n-4);
        a=mul(a,t);
        ll ans=a.temp[0][0]%mod;
        printf("%I64d
",ans);
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/shuaihui520/p/10002245.html