问题描述
集合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
对于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; } }