zoukankan      html  css  js  c++  java
  • 线性规律题目的求解与心得

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

    解题分几个步骤;

    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
  • 相关阅读:
    五十二、使用Adb命令卸载android应用配置方法
    五十五、application用法
    五十七、SlidingDrawer (抽屉)的用法
    五十三、android启动过程
    六十、百度地图
    六十一、ListView,GridView和ScrollView上拉刷新和下拉更多
    显示设备信息
    打开HTML代码对应的页面
    体质指数计算
    OpenWebPage
  • 原文地址:https://www.cnblogs.com/shuaihui520/p/10002245.html
Copyright © 2011-2022 走看看