1251 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+m1iji1Cjm1m a n s = ∑ i = 2 n C n + m − 1 − i − 1 m − 1 m + ∑ j = 1 m − 1 ( − 1 ) j C n + m − 1 − i j − i − 1 m − 2 C m − 1 j m

因为 n+m1iji1>m2 n + m − 1 − i j − i − 1 > m − 2 所以这个式子是可以 nlogn n l o g n 算出来的。
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);
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值