• CodeAction_beta02(DP)


    用第1个,第2个...第N个斐波那契数构成一个长度为P的序列,每个斐波那契数可以使用任意多次,但至少要使用一次,并且序列中任意两个相同的斐波那契数之间至少要隔着 M 个数, 求满足条件的序列组成方法有多少种?输出答案对1e9+7取模.

    (fib[i])表示第i个斐波那契数,(fib[0]=fib[1]=1),(fib[i]=fib[i−1]+fib[i−2](i>1)).

    分析:本来标题是想叫做"与fib完全无关的一道fib题".不过个人认为这的确是道思维好题.

    因为题目说了所有数都要出现至少一次 所以只需考虑其组合而不用考虑其排列 最后乘个n!就是答案.(意思就是可以当做这 N 个数是无序的)所以说本题与fib无关,你就当做题目给你了n个数就行了.

    (f[i][j])表示序列前i个放了j种数的方案数.考虑放第i+1个时的状态转移.

    不难想到,此时我们有两种选择.

    (1)放一个新的数,则状态转移为(f[i+1][j+1])

    (2)放一个之前已经出现过的数,则状态转移为(f[i+1][j])

    对于第一种情况,有(f[i+1][j+1]+=f[i][j]);

    对于第二种情况,因为"序列中任意两个相同的斐波那契数之间至少要隔着M个数",所以序列末尾的M种数是不可以放的,则有(f[i+1][j]+=f[i][j]*(j-m))

    注意一边算一边取模,然后"十年oi一场空,不开long long..."

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    inline int read(){
        int s=0,w=1;
        char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
        return s*w;
    }
    const int mod=1e9+7;
    int n,m,p;
    ll ans,f[2005][2005];
    int main(){
        n=read();m=read();p=read();
        f[0][0]=1;
        for(int i=0;i<=p;i++)
    	for(int j=0;j<=n;j++){
    	    f[i+1][j+1]+=f[i][j]%mod;
    	    if(j>m)f[i+1][j]=(f[i+1][j]+f[i][j]*(j-m))%mod;
    	}
        ans=f[p][n]%mod;
        for(int i=1;i<=n;i++)
    	ans=(ans*i)%mod;
        cout<<ans<<endl;
        return 0;
    }
    
    
  • 相关阅读:
    奈良有鹿
    Luogu P1892 团伙
    Luogu P1330 封锁阳光大学
    java读取property文件
    collection
    testNG学习
    maven项目学习
    Android.mk详解二
    sdk开发经验
    工作经验
  • 原文地址:https://www.cnblogs.com/PPXppx/p/10322496.html
Copyright © 2020-2023  润新知