BZOJ4599[JLoi2016&LNoi2016]成绩比较(dp+拉格朗日插值)

这个题我们首先可以dp,f[i][j]表示前i个科目恰好碾压了j个人的方案数,然后进行转移。我们先不考虑每个人的分数,先只关心和B的相对大小关系。我们设R[i]为第i科比B分数少的人数,则有f[i][j]=sum f[i-1][k]*C(k,j)*C(n-1-k,R[i]-j)  (k>=j) 怎么解释呢,首先前i-1科有k个人已经被碾压,k肯定大于等于j,然后考虑当前这一科有j个人被碾压,那么就需要从k个人中选出j个来即C(k,j),然后从剩下的有R[i]-j个人比B考的少,这些人必须是之前i-1科里就没有被碾压的人,所以再乘上一个C(n-1-j,R[i]-k),到此我们dp完了,可是我们还需要算上每个人的分数,这个东西很明显可以乘上我们的f[m][k]得到答案。 这些分数的方案数是什么呢?对于第i科成绩,有n-R[i]-1个人比B考的多,有R[i]个人比B少,因为我们之前考虑了相对大小关系,这里直接很明显的算就行了就是

然后我们算n次sigam即可,把他们乘在一起。但是由于Ui是1e9级别的,直接暴力算肯定会超时,我们可以用拉格朗日插值来算。

很明显这是一个n次的多项式,所以我们利用插值就可以算出答案了。 —— by VANE

#include<iostream>
#include<cstdio>
#include<cstring>
#define MN 105
#define mod 1000000007
using namespace std;
inline int read()
{
    int x = 0 , f = 1; char ch = getchar();
    while(ch < ‘0‘ || ch > ‘9‘){ if(ch == ‘-‘) f = -1;  ch = getchar();}
    while(ch >= ‘0‘ && ch <= ‘9‘){x = x * 10 + ch - ‘0‘;ch = getchar();}
    return x * f;
}
int inv[MN+5],Inv[MN+5],p[MN+5],U[MN+5],R[MN+5],n,m,K,f[MN+5][MN+5];

inline int pow(int x,int k)
{
    int sum=1;
    for(;k;k>>=1,x=1LL*x*x%mod)
        if(k&1) sum=1LL*sum*x%mod;
    return sum;
}
inline int C(int n,int m){return 1LL*p[n]*Inv[m]%mod*Inv[n-m]%mod;}
inline void Re(int&x,int y){x+=y;x>=mod?x-=mod:0;}

inline int Calc(int m,int rk)
{
    if(m<=n+1)
    {
        int res=0;
        for(int i=1;i<=m;++i)
            res=(res+1LL*pow(i,rk)*pow(m-i,n-rk-1))%mod;
        return res;
    }
    int sum=1,res=0,Div=1,S=0;
    for(int i=1;i<=n+1;++i) sum=1LL*sum*(m-i+mod)%mod;
    for(int i=2;i<=n+1;++i) Div=1LL*Div*(1-i+mod)%mod;
    for(int i=1;i<=n+1;++i)
    {
        int t=1LL*sum*pow(m-i+mod,mod-2)%mod;
        S=(S+1LL*pow(i,rk)%mod*pow(m-i,n-rk-1))%mod;
        t=1LL*t*S%mod;
        res=(res+1LL*t*pow(Div,mod-2))%mod;
        Div=1LL*Div*pow(mod-(n-i+1),mod-2)%mod*i%mod;
    }
    return res;
}

int main()
{
    n=read();m=read();K=read();
    for(int i=1;i<=m;++i) U[i]=read();
    for(int i=1;i<=m;++i) R[i]=n-read();
    inv[0]=inv[1]=p[0]=p[1]=Inv[0]=1;
    for(int i=2;i<=MN;++i)
        p[i]=1LL*p[i-1]*i%mod,
        inv[i]=1LL*(mod-mod/i)*inv[mod%i]%mod;
    for(int i=1;i<=MN;++i)
        Inv[i]=1LL*Inv[i-1]*inv[i]%mod;
    f[0][n-1]=1;
    R[0]=n-1;
    for(int i=1;i<=m;++i)
        for(int j=0;j<=R[i];++j)
            for(int k=j;k<=R[i-1];++k)
            if(n-1-k>=R[i]-j)
            Re(f[i][j],1ll*f[i-1][k]*C(k,j)%mod*C(n-1-k,R[i]-j)%mod);
    int ans=f[m][K];
    for(int i=1;i<=m;++i) ans=1LL*ans*Calc(U[i],R[i])%mod;
    cout<<ans<<endl;
    return 0;
}

原文地址:https://www.cnblogs.com/nbwzyzngyl/p/8394921.html

时间: 2024-10-08 13:15:54

BZOJ4599[JLoi2016&LNoi2016]成绩比较(dp+拉格朗日插值)的相关文章

bzoj 4559 [JLoi2016]成绩比较 —— DP+拉格朗日插值

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4559 看了看拉格朗日插值:http://www.cnblogs.com/ECJTUACM-873284962/p/6833391.html https://blog.csdn.net/lvzelong2014/article/details/79159346 https://blog.csdn.net/qq_35649707/article/details/78018944 还只会最简单的

[CF995F]Cowmpany Cowmpensation[树形dp+拉格朗日插值]

题意 给你一棵树,你要用不超过 \(D\) 的权值给每个节点赋值,保证一个点的权值不小于其子节点,问有多少种合法的方案. \(n\leq 3000, D\leq 10^9\) 分析 如果 \(D\) 比较小的话可以考虑状态 \(f_{i,j}\) 表示点 \(i\) 的权值是 \(j\) 的方案总数,\(g_{i,j}\) 表示 \(\sum_\limits{k=1}^jf_{i,j}\) ,转移也比较显然:\(f_{i,j}=\prod g_{son,j}\) 先证明结论:前?\(n\)?个正

【BZOJ】4559: [JLoi2016]成绩比较 计数DP+排列组合+拉格朗日插值

[题意]n位同学(其中一位是B神),m门必修课,每门必修课的分数是[1,Ui].B神碾压了k位同学(所有课分数<=B神),且第x门课有rx-1位同学的分数高于B神,求满足条件的分数情况数.当有一位同学的一门必修课分数不同时视为两种情况不同.n,m<=100,Ui<=10^9. [算法]计数DP+排列组合+拉格朗日插值 [题解]把分数作为状态不现实,只能逐门课考虑. 设$f[i][j]$表示前i门课,有j个同学被碾压的情况数,则有: $$f[i][j]=g(i)\cdot\sum_{k=j

【BZOJ】2655: calc 动态规划+拉格朗日插值

[题意]一个序列$a_1,...,a_n$合法当且仅当它们都是[1,A]中的数字且互不相同,一个序列的价值定义为数字的乘积,求所有序列的价值和.n<=500,A<=10^9,n+1<A<mod<=10^9,mod是素数. [算法]动态规划+拉格朗日插值 [题解]这道题每个数字的贡献和序列选了的数字积关系密切,所以不能从序列角度考虑(和具体数字关系不大). 设$f_{n,m}$表示前n个数字(值域)中取m个数字的答案,那么枚举取或不取数字n,取n时乘n且有j个位置可以插入,即:

【数值分析】拉格朗日插值与牛顿插值

在工程应用和科学研究中,经常要研究变量之间的关系y=f(x).但对于函数f(x),常常得不到一个具体的解析表达式,它可能是通过观测或实验得到的一组数据(x,f(x)),x为一向量;或则是解析表达式非常复杂,不便于计算和使用.因此我们需要寻找一个计算比较简单的函数S(x)近似代替f(x),并使得S(x)=f(x),这种方法就称为插值法. 常用的插值法有: 一维插值法:拉格朗日插值.牛顿插值.分段低次插值.埃尔米特插值.样条插值. 二维插值法:双线性插值.双二次插值. 拉格朗日插值法 已知函数f(x

拉格朗日插值Python代码实现

1. 数学原理 对某个多项式函数有已知的k+1个点,假设任意两个不同的都互不相同,那么应用拉格朗日插值公式所得到的拉格朗日插值多项式为: 其中每个lj(x)为拉格朗日基本多项式(或称插值基函数),其表达式为: 2. 轻量级实现 利用 直接编写程序,可以直接插值,并且得到对应的函数值.但是不能得到系数,也不能对其进行各项运算. def h(x,y,a): ans=0.0 for i in range(len(y)): t=y[i] for j in range(len(y)): if i !=j:

Educational Codeforces Round 7 F - The Sum of the k-th Powers 拉格朗日插值

The Sum of the k-th Powers There are well-known formulas: , , . Also mathematicians found similar formulas for higher degrees. Find the value of the sum modulo 109 + 7 (so you should find the remainder after dividing the answer by the value 109 + 7).

拉格朗日插值

一,介绍 学过FFT的人都应该知道什么叫做插值,插值的意思就是说将一个多项式从点值表达转变成系数表达. 在FFT的插值中为什么可以做到n log n,是因为单位复数根的关系. 那对于普通的插值应该怎么办呢?解方程是一种方法,但是这个在计算机中十分不现实. 所以有许多种插值的方法,其中比较普及的就是拉格朗日插值. 二,定义 对某个多项式函数,已知有给定的k + 1个取值点: 其中对应着自变量的位置,而对应着函数在这个位置的取值. 假设任意两个不同的xj都互不相同,那么应用拉格朗日插值公式所得到的拉

python拉格朗日插值

#拉格朗日插值代码 import pandas as pd #导入数据分析库Pandas from scipy.interpolate import lagrange #导入拉格朗日插值函数 inputfile = '../data/catering_sale.xls' #销量数据路径 outputfile = '../tmp/sales.xls' #输出数据路径 data = pd.read_excel(inputfile) #读入数据 data[u'销量'][(data[u'销量'] < 4