試題 算法提高 翔集合(矩陣快速冪)


問題描述
  集合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;
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM