[JLOI 2016] bzoj 4559 成绩比较 - 计数 - 容斥 - 拉格朗日插值

35 篇文章 0 订阅
18 篇文章 0 订阅

计数至少有k名学生被碾压
发现此时除了那一堆组合数,答案是每一门课程满足其人排名是r的方案数的乘积。
考虑这个怎么算,设f_i(x)表示第i门课程其人分数是x且排名是r_i的方案数,显然是一个n-1次多项式。要对这个求前缀和,变成了一个n次多项式。发现该多项式不算组合数的部分与k无关可以预处理。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<assert.h>
#define N 110
#define mod 1000000007
#define lint long long
#define gc getchar()
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
inline int inn()
{
    int x,ch;while((ch=gc)<'0'||ch>'9');
    x=ch^'0';while((ch=gc)>='0'&&ch<='9')
        x=(x<<1)+(x<<3)+(ch^'0');return x;
}
int f[N],fac[N],facinv[N],r[N],u[N],pre[N],suf[N],s[N],si[N];
inline int mol(lint x) { return x%=mod,(x<0?x+mod:x); }
inline int sol(lint x,int s) { return x%=mod,((s&1)?(mod-x)%mod:x); }
inline int fast_pow(int x,int k,int ans=1)
{   for(;k;k>>=1,x=(lint)x*x%mod) (k&1)?ans=(lint)ans*x%mod:0;return ans;   }
inline int calcf(int n,int i,int x)
{
    return (lint)fast_pow(mol(u[i]-x),r[i]-1)*fast_pow(x,n-r[i])%mod;
}
inline int fz(int j)
{
    return (lint)pre[j-1]*suf[j+1]%mod;
}
inline int fm(int n,int j)
{
    return sol((lint)facinv[j-1]*facinv[n+1-j],n+1-j);
}
inline int C(int n,int m) { return (lint)fac[n]*facinv[m]%mod*facinv[n-m]%mod; }
inline int prelude(int n)
{
    for(int i=fac[0]=1;i<=n;i++) fac[i]=(lint)fac[i-1]*i%mod;
    facinv[n]=fast_pow(fac[n],mod-2);
    for(int i=n-1;i>=0;i--) facinv[i]=facinv[i+1]*(i+1ll)%mod;
    return 0;
}
int main()
{
    int n=inn(),m=inn(),qk=inn();prelude(n);
    for(int i=1;i<=m;i++) u[i]=inn();int mxr=0;
    for(int i=1;i<=m;i++) mxr=max(mxr,r[i]=inn());
    if(qk>n-mxr) return !printf("%d\n",0);
    for(int i=1;i<=m;i++)
    {
        pre[0]=suf[n+2]=1,si[i]=0;
        for(int j=1;j<=n+1;j++) s[j]=(s[j-1]+calcf(n,i,j))%mod;
        for(int j=1;j<=n+1;j++) pre[j]=(lint)pre[j-1]*mol(u[i]-j)%mod;
        for(int j=n+1;j>=1;j--) suf[j]=(lint)suf[j+1]*mol(u[i]-j)%mod;
        for(int j=1;j<=n+1;j++)
            (si[i]+=(lint)s[j]*fz(j)%mod*fm(n,j)%mod)%=mod;
    }
    for(int k=qk;k<=n-mxr;f[k]=(lint)f[k]*C(n-1,k)%mod,k++)
        for(int i=f[k]=1;i<=m;i++) f[k]=(lint)f[k]*si[i]%mod*C(n-k-1,r[i]-1)%mod;
    for(int k=n-mxr,r;k>=qk;f[k]=mol(f[k]-r),k--)
        for(int i=(r=0)+k+1;i<=n-mxr;i++) (r+=(lint)C(i,k)*f[i]%mod)%=mod;
    return !printf("%d\n",f[qk]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值