bzoj4402 Claris的剑

229 篇文章 0 订阅

由于本质不同的约束条件,我们只需要考虑字典序最小的序列。而字典序最小的序列一定长成这样

1,2,1,2,3,2,3,...,m1,m,m1,m

或者
1,2,1,2,3,2,3,...,m1,m,m1

第一种可以看成是 1,2,3,...,m 插入若干个 (i,i+1) 形成,第二种可以删去最后一个 m1 ,看成是序列长度为 n1 的第一种。于是我们枚举最大值 m ,只需要解决计算第一种方案的个数。
我们还剩下nm个位置,必须一选选一对,而且只有 m1 种选法。因此相当于有 nm2 个球放到 m1 个筐里,可以有球不放,可以有筐为空的方案数,显然是 ((nm)/2+mm)

#include<cstdio>
#include<algorithm>
using namespace std;
#define LL long long
const int maxn=4000010,p=1000000007;
int fac[maxn],inv[maxn],n,m;
int pow(int base,int k)
{
    int ret=1;
    for (;k;k>>=1,base=(LL)base*base%p)
        if (k&1) ret=(LL)ret*base%p;
    return ret;
}
int c(int n,int k)
{
    if (k>n) return 0;
    return (LL)fac[n]*inv[k]%p*inv[n-k]%p;
}
int inc(int x,int y)
{
    x+=y;
    return x>=p?x-p:x;
}
int main()
{
    int mx,ans=1;
    scanf("%d%d",&n,&m);
    if ((LL)n*m==0)
    {
        printf("0\n");
        return 0;
    }
    m=min(n,m);
    mx=(n-m)/2+m-1;
    fac[0]=inv[0]=1;
    for (int i=1;i<=mx;i++) fac[i]=(LL)fac[i-1]*i%p;
    inv[mx]=pow(fac[mx],p-2);
    for (int i=mx-1;i>=1;i--) inv[i]=(LL)inv[i+1]*(i+1)%p;
    for (int i=2;i<=m;i++)
        ans=inc(ans,inc(n-1-i>=0?c((n-1-i)/2+i-1,i-1):0,c((n-i)/2+i-1,i-1)));
    printf("%d\n",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值