• 算法训练 猴子吃包子-构造


    问题描述
      集合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

    本题需要矩阵乘法求解。我们假设an为最大数为n时包含所有翔集合的总数,分析他的组成,可以由含有n和不含有n的翔集合相加。
    1,不含有n的翔集合总数显然为an-1。
    2,而含有n的如何分析呢,我们可以这样想,因为翔集合每个元素之间的差的绝对值大于2,所以我们可以在最大数为n-3时构成的每一个翔集合中后面都加一个n,但是由于翔集合中元素数量最少为2,这样构成后,显然只包含了3个及以上的含n的翔集合an-3。
    3,单独分析含n的二元翔集合,很简单为n-3个,即n与不大于n-3的数构成的二元集,
    综上得出通项:an = an-1+an-3+(n-3)
    滚动数组或矩阵乘法求出即可。

    得出通项后可构造矩阵

     代码:

    #include<iostream>
    #include<stdio.h>
    using namespace std;
    typedef long long ll;
    const int mod = 1e6+7;
    struct node{
        ll A[5][5];
        node(){
            for(int i=0;i<5;i++){
                for(int j=0;j<5;j++){
                    A[i][j] = 0;
                }
            }
        }
    }x,y;
    ll n;
    void set(){
        x.A[0][0]=x.A[0][2]=x.A[0][3]=1;
        x.A[1][0]=1;
        x.A[2][1]=1;
        x.A[3][3]=x.A[3][4]=1;
        x.A[4][4]=1; 
        
        y.A[3][0]=1;
        y.A[4][0]=1;
    } 
    struct node Mul(node tmp1,node tmp2){
        node tmp3;
        for(int i=0;i<5;i++){
            for(int j=0;j<5;j++){
                for(int k=0;k<5;k++){
                    tmp3.A[i][j]=(tmp3.A[i][j]+tmp1.A[i][k]*tmp2.A[k][j])%mod; 
                }
            }
        }
        return tmp3;
    }
    
    struct node quick2_pow(ll k){
        node ans = x;
        while(k){
            if(k&1) ans = Mul(ans,x);
            x = Mul(x,x);
            k>>=1;    
        }
        return ans;
    } 
    
    int main(){
        set();
        cin>>n;
        if(n<4){
            cout<<"0"<<endl;
            return 0;
        }
        node s;
        s = Mul(quick2_pow(n-4),y);
        cout<<s.A[0][0]%mod<<endl; 
        return 0; 
    }
  • 相关阅读:
    java执行构造器和初始化字段的顺序
    java语言中的varargs
    对Java语言的byte类型变量进行无符号提升
    VisualStudio 切换帐号 (原帐号已过期且无法登录时用)
    C/C++ 的关系运算符采用短路运算
    实现std::string的ltrim、rtrim和trim方法
    Excel 用于批量把单元格设置为"文本格式保存的数字"的宏
    为什么要用webUI?
    CEF3中js调用delphi内部方法
    2016-1-1最新版本的linphone-android在mac上编译通过,同时建立了IDEA工程
  • 原文地址:https://www.cnblogs.com/lusiqi/p/13762793.html
Copyright © 2020-2023  润新知