zoukankan      html  css  js  c++  java
  • 试题 算法提高 翔集合(矩阵快速幂)

    问题描述
      集合M至少有两个元素(实数),且M中任意两个元素差的绝对值都大于2,则称M为“翔集合”,已知集合S={1,2...,n},请求出n的子集中共有多少个翔集合。
    输入格式
      输入共一行,一个整数n.(n>=2)
    输出格式
      输出共一行,一个整数表示S的子集中共有多少个翔集合,由于个数可能过大,请输出这个值除以1000007的余数。
    样例输入
    4
    样例输出
    1
    数据规模和约定
      对于20%的数据,2<=n<=1000000
      对于100%的数据,2<=n<=10^15
    思路
    先想出递推式,当n>=4,考虑f[n]的翔集合数量。
    当集合不包含最后一项n,有f[n-1]个;
    当集合包含最后一项,1.当n-1,n-2不在集合中,第n项和前n-3项满足的翔集合均可构成翔集合,有f[n-3]个;
    2.当每个翔集合只含2个数(含n),则有n-3个;
    则推出f[n]=f[n-1]+f[n-3]+n-3;
    观察数据规模,不能直接dp递推,选择矩阵快速幂求解;
    我们构成一个矩阵A1=[  f[n-1], f[n-2], f[n-3], n-3, 1 ];
    则有A2 = [ f[n], f[n-1], f[n-2], n-2, 1 ];
    构造矩阵B使得A1*B=A2;
    计算得  B=

     则所以要得到第n项的翔集合数通过[ f[3] f[2] f[1] 1 1 ]*B^n-3 取第一行第一列即是所求f[n]。

    对B^n-3进行矩阵快速幂即可。

    code:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long int ll;
    struct mat{
        ll m[6][6];
    }unit;
    ll n;
    const ll mod=1e6+7;
    mat mul(mat a1,mat a2){
        mat temp;
        for(int i=1;i<=5;i++){
            for(int j=1;j<=5;j++){
                    temp.m[i][j]=0;
                for(int k=1;k<=5;k++){
                    temp.m[i][j]=(temp.m[i][j]+(a1.m[i][k]*a2.m[k][j])%mod)%mod;
                }
            }
        }
        return temp;
    }
    ll quick_mat(ll n){
        mat ans;
        memset(ans.m,0,sizeof(ans.m));
        for(int i=1;i<=5;i++)ans.m[i][i]=1;
        while(n){
            if(n&1)ans=mul(ans,unit);
            unit=mul(unit,unit);
            n>>=1;
        }
        mat tot;
        tot.m[1][1]=0,tot.m[1][2]=0,tot.m[1][3]=0,tot.m[1][4]=1,tot.m[1][5]=1;
        ll sum=0;
        for(int i=1;i<=5;i++){
            sum+=tot.m[1][i]*ans.m[i][1];
            sum%=mod;
        }
        return sum;
    }
    int main(){
        cin>>n;
        if(n==1||n==2){cout<<"0"<<endl;return 0;}
        else if(n==3){cout<<"1"<<endl;return 0;}
        else{
            unit.m[1][1]=1,unit.m[1][2]=1,unit.m[1][3]=0,unit.m[1][4]=0,unit.m[1][5]=0;
            unit.m[2][1]=0,unit.m[2][2]=0,unit.m[2][3]=1,unit.m[2][4]=0,unit.m[2][5]=0;
            unit.m[3][1]=1,unit.m[3][2]=0,unit.m[3][3]=0,unit.m[3][4]=0,unit.m[3][5]=0;
            unit.m[4][1]=1,unit.m[4][2]=0,unit.m[4][3]=0,unit.m[4][4]=1,unit.m[4][5]=0;
            unit.m[5][1]=0,unit.m[5][2]=0,unit.m[5][3]=0,unit.m[5][4]=1,unit.m[5][5]=1;
            cout<<quick_mat(n-3)<<endl;
            return 0;
        }
    }
  • 相关阅读:
    9、二叉排序树的创建、插入、遍历
    8、判断两个链表是否相交
    7、判断链表是否有环
    6、查找单链表中倒数第n个节点
    5、单链表的反转
    4、KMP(看毛片)算法
    3、希尔排序
    2、快速排序
    json字符串转为json对象
    json对象转化为字符串过程分析
  • 原文地址:https://www.cnblogs.com/mohari/p/13532219.html
Copyright © 2011-2022 走看看