1251 Fox序列的数量

Fox序列计数
本文介绍了一种特定类型的序列——Fox序列,并提供了一种计算给定长度和元素范围内的所有可能Fox序列数量的方法。通过数学公式和算法实现,解决了计算此类序列的问题。

题意:

一个单调非递减序列被称为 Fox 序列,当且仅当序列里边出现频率最高的元素是唯一的。
例如:序列 1, 1, 2, 3, 4 是一个 Fox 序列, 因为它符合定义。出现频率最高的元素是1,它出现了2次,并且没有别的元素出现的次数为2。
但是序列 1, 1, 2, 2 不是 Fox 序列, 因为1 和 2 都出现了2次,不是唯一的。
注意: 序列 2, 1, 1 不是 Fox 序列, 因为他不是单调非递减的序列。
给出N,M,计算有多少个长度为N的 Fox 序列,满足序列的所有元素都 >= 1并且 <= M。由于结果很大,输出Mod 1000000007的结果。
例如:N = 3,M = 2。满足条件的序列为:1 1 1, 2 2 2, 1 1 2, 1 2 2,共4个。

题解:

枚举出现次数最多的数的个数,稍微容斥一下可得:

ans=i=2nCm1n+m1i1m+j=1m1(1)jCm2n+m1iji1Cjm1mans=∑i=2nCn+m−1−i−1m−1m+∑j=1m−1(−1)jCn+m−1−ij−i−1m−2Cm−1jm

因为n+m1iji1>m2n+m−1−ij−i−1>m−2所以这个式子是可以nlognnlogn算出来的。
code:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#define LL long long
using namespace std;
const LL mod=1e9+7;
LL f[200010],inv[200010];
int n,m;
void pre()
{
    f[0]=f[1]=inv[0]=inv[1]=1;
    for(int i=2;i<=200010;i++) f[i]=f[i-1]*i%mod,inv[i]=(mod-mod/i)*inv[mod%i]%mod;
    for(int i=2;i<=200010;i++) inv[i]=inv[i-1]*inv[i]%mod;
}
LL C(int n,int m)
{
    if(n>m) return 0;
    return f[m]*inv[m-n]%mod*inv[n]%mod;
}
int main()
{
    pre();
    int T;scanf("%d",&T);
    while(T--)
    {
        scanf("%d %d",&n,&m);
        if(m==1) {printf("1\n");continue;}
        if(n==1) {printf("%d\n",m);continue;}
        LL ans=0;
        for(int i=2;i<=n;i++)
        {
            ans=(ans+C(m-2,n+m-1-i-1))%mod;
            for(int j=1;j<=m-1;j++)
            {
                if(n+m-1-i*j-i-1<m-2) break;
                ans=(ans+((j&1)?-1:1)*C(m-2,n+m-1-i*j-i-1)*C(j,m-1)%mod)%mod;
            }
        }
        printf("%lld\n",ans*m%mod);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值