【bzoj4559】成绩比较
补档计划
借这题补个档——拉格朗日插值
插值的话大概就是有一个\(n-1\)次多项式\(A(x)\),你只知道它在\(n\)处的点值,分别是\((x_1,y_1),(x_2,y_2),...,(x_{n},y_{n})\),让你还原这个多项式
关于插值我们有很多的方法,有十分粗暴的高消\(O(n^3)\),也有十分优秀的快速差值(不会qwq),还有拉格朗日插值法\(O(n^2)\)(emmm如果说取值位置连续的话。。可以做到\(O(n)\))
其实拉格朗日差值的核心就是这两条式子:
l_j(x)&=\sum\limits_{i=0,i\neq j}^n\frac{x-x_i}{x_j-x_i}\\
A(x)&=\sum\limits_{i=1}^{n}y_i\cdot l_i(x)
\end{aligned}
\]
具体为什么的话就是,首先有\(n\)个处点值是可以确定一个\(n-1\)次多项式,并且这个多项式是惟一的,那么接下来就是看为什么这样构造是满足条件的:我们观察\(l_j(x)\)这个多项式的值,当代进去的值为\(x_i\)中的其中一个时,这个多项式才会为\(1\),否则为\(0\),所以乘上一个\(y_i\)然后求一下和就可以满足这\(n\)处的取值了
然后就是这个东西怎么比较。。快一点的求
大概是。。我们可以先求出\(C(x)=\sum\limits_{i=1}^n(x-x_i)\)这个多项式各项系数(可以在\(O(n)\)的时间内得到,具体的话就是考虑每次暴力拆括号然后未知数的幂指数\(+1\),然后系数要乘上\(-x_i\)),求出这个东西之后,我们就可以在\(O(n)\)的时间内求出\(B_j(x)=\sum\limits_{i=1,i\neq j}^n(x-x_i)\)(具体就是直接考虑将\((x-x_j)\)这项的贡献去掉就好了),然后我们又可以用\(B_j(x)\)求出分母然后其他的随便乱搞都可以了
那为什么说取值位置连续的话可以\(O(n)\)呢?其实。。因为是连续的所以我们的分子可以用阶乘什么的乱搞,然后分母维护一个前缀乘积,一个后缀乘积就好了(实际上好像前缀成绩后缀乘积这个东西完全可以在非连续情况下使用但是反正分母那里要\(O(n)\)又何必搞那么麻烦呢嘿嘿。。。)
这里贴一下非连续取值的时候的代码(虽然说这题根本不用不过反正都是补档嘛。。一起写好了)
void solve(int n){
memset(c,0,sizeof(c));
c[0]=1;
for (int i=1;i<=n;++i){
for (int j=n;j>=0;--j){
c[j+1]=(c[j+1]+c[j])%MOD;
c[j]=(-c[j]*X[i])%MOD;
}
}//get 系数 of \prod_{i=0}^k (x-x_i)
ll s=0,tmp=1;
for (int i=1;i<=n;++i){
memcpy(d,c,sizeof(d));
memset(b,0,sizeof(b));
for (int j=n;j>=0;--j){
b[j]=d[j+1];
d[j]=(d[j]+d[j+1]*X[i])%MOD;
d[j+1]=0;
}//take (x-x_i) out of \prod_{j=0}^k (x-x_j)
s=0,tmp=1;
for (int j=0;j<=n;++j){
s=(s+tmp*b[j])%MOD;
tmp=tmp*X[i]%MOD;
}//get \prod_{j=0,j!=i}^k (x_i-x_j)
s=ksm(s,MOD-2)*Y[i]%MOD;
for (int j=0;j<=n;++j) b[j]=b[j]*s%MOD;//get the final 系数
for (int j=0;j<=n;++j)
ans[j]=(ans[j]+b[j])%MOD;
}
}
Solution
然后我们来看这题
这题的做法很多。。网上有十分优秀的根本不需要拉格朗日插值的做法。。但是我比较菜所以。。
考虑一下这个答案要怎么算,因为题目的限制条件有点多所以我们考虑将它拆成两个部分来想:
1.先不管具体分数是多少,只考虑相对大小,求出满足有恰好\(K\)个人各门分数都小于等于\(B\)神的方案数,记为\(ans1\)
2.算具体分数是多少
那么最后的答案就应该是\(ans1\)再乘上对应的第二部分中具体分数不同的贡献
我们先来考虑第一部分,这里。。我们考虑用dp+容斥来求解(注意,接下来的dp中所有的转移都不考虑每个人的具体得分,我们在第一部分的求解中只考虑相对大小)
记\(f[i]\)表示至少\(i\)个人满足条件的方案数,那么我们可以得到:
\]
其中\(R_j\)表示的是\(B\)神在第\(j\)门科目中的排名,这个式子具体一点的含义的话就是:首先我们需要钦定\(i\)个人是满足条件的,所以总共是\(\binom {n-1}i\)中选法,然后在钦定了\(i\)个人一定排在\(B\)神之后的前提下,我们对于每一门科目又要满足有\(R_j-1\)个人分数大于\(B\)神,那只能从\(n-1-i\)个人中选,所以就是后面的按个组合数了
有了这个东西之后我们构造一下容斥系数\(a(i)\):
\]
其实仔细想一下就可以得出:
\]
具体一点就是你考虑\(f[i]\)的含义就是至少\(i\)个人满足条件,那么这个\(K\)个人中一旦有\(i\)个人是被钦定的,\(f[i]\)就会被算一次,所以乘个系数就好了
然后第一部分我们就算完了
接着是第二部分(这部分才到插值==)
第二部分的话,我们要考虑每个人具体是什么分数了,我们要求的东西其实就是要求有\(x\)个人比\(B\)神低,\(y\)个人比\(B\)神高的分数有多少种(与第一部分不同的是,这里不需要考虑具体是哪一个人,而是考虑分数)
那么对于一门科目\(i\),我们有\(y=R_i-1,x=(n-1)-y\), 所以我们只要枚举一下\(B\)神的分数就好了:
\]
其中\(U_i\)表示这门科目分数上限
那么所有的科目的总贡献就是:
\]
最终答案就是\(ans1*ans2\)啦
但是我们看\(U_i\)的范围是\(10^9\),所以。。不能直接算,又发现如果说我们将\(U_i\)看成一个变量的话,每门科目的贡献可以看成一个\(n\)次多项式\(P(x)\)(次数最高只能到\(n\)),那所以我们可以先暴力带入\(x=0...n\),然后把这\(n+1\)个点值算出来,然后每次\(O(n^2)\)求值就好了(具体的话就是直接代进拉格朗日插值的那条式子)
总的时间复杂度\(O(n^3)\)(其实。。求值好像可以做到每次\(O(n)\)的。。不过\(n=100\)我就写了最暴力的这种了qwq)
代码大概长这个样子
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=110,MOD=1e9+7;
int u[N],r[N],f[N],c[N][N],g[N];
int n,m,K,ans1,ans2;
int add(int x,int y){return (1LL*x+y)%MOD;}
int mul(int x,int y){return 1LL*x*y%MOD;}
void predp(){
c[0][0]=1;
for (int i=1;i<=n;++i){
c[i][0]=1; c[i][i]=1;
for (int j=1;j<i;++j)
c[i][j]=add(c[i-1][j],c[i-1][j-1]);
}
for (int i=1;i<=n;++i){
f[i]=c[n-1][i];
for (int j=1;j<=m;++j)
f[i]=mul(f[i],c[n-1-i][r[j]-1]);
}
}
int ksm(int x,int y){
int ret=1,base=x;
for (;y;y>>=1,base=mul(base,base))
if (y&1) ret=mul(ret,base);
return ret;
}
void precalc(int U,int R,int &val){
int tmp;
val=0;
for (int i=1;i<=U;++i){
tmp=mul(ksm(U-i,R-1),ksm(i,(n-1)-(R-1)));
val=add(val,tmp);
}
}
int calc(int x){
int fz,fm,ret=0;
for (int i=0;i<=n;++i){
fz=1; fm=1;
for (int j=0;j<=n;++j){
if (j==i) continue;
fz=mul(fz,(x-j+MOD)%MOD);
fm=mul(fm,(i-j+MOD)%MOD);
}
ret=add(ret,1LL*fz*ksm(fm,MOD-2)%MOD*g[i]%MOD);
}
return ret;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
#endif
scanf("%d%d%d",&n,&m,&K);
for (int i=1;i<=m;++i) scanf("%d",u+i);
for (int i=1;i<=m;++i) scanf("%d",r+i);
predp();
ans1=0;
for (int i=K;i<=n;++i){
if ((K-i)%2==0)
ans1=add(ans1,mul(c[i][K],f[i]));
else
ans1=add(ans1,(1LL*MOD-mul(c[i][K],f[i]))%MOD);
}
ans2=1;
for (int i=1;i<=m;++i){
if (i==6)
int debug=1;
for (int j=0;j<=n;++j)
precalc(j,r[i],g[j]);
ans2=mul(ans2,calc(u[i]));
}
printf("%d\n",mul(ans1,ans2));
}
【bzoj4559】成绩比较的更多相关文章
- BZOJ4559 成绩比较
题目传送门 分析: 我们可以先试着求一下,对于单个学科,有多少种分配方案可以使B神排名为R 对于第i个学科 \(~~~~g(i)=\sum_{j=1}^{H_i}j^{n-R_i}(H_i-j)^{R ...
- 【BZOJ4559】成绩比较(动态规划,拉格朗日插值)
[BZOJ4559]成绩比较(动态规划,拉格朗日插值) 题面 BZOJ 洛谷 题解 显然可以每门课顺次考虑, 设\(f[i][j]\)表示前\(i\)门课程\(zsy\)恰好碾压了\(j\)个\(yy ...
- 【BZOJ4559】[JLoi2016]成绩比较 动态规划+容斥+组合数学
[BZOJ4559][JLoi2016]成绩比较 Description G系共有n位同学,M门必修课.这N位同学的编号为0到N-1的整数,其中B神的编号为0号.这M门必修课编号为0到M-1的整数.一 ...
- 【BZOJ4559】成绩比较(组合计数,容斥原理)
题意: G系共有n位同学,M门必修课.这N位同学的编号为0到N-1的整数,其中B神的编号为0号.这M门必修课编号为0到M- 1的整数.一位同学在必修课上可以获得的分数是1到Ui中的一个整数.如果在每门 ...
- bzoj4559[JLoi2016]成绩比较 容斥+拉格朗日插值法
4559: [JLoi2016]成绩比较 Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 261 Solved: 165[Submit][Status ...
- BZOJ4559: [JLoi2016]成绩比较(dp 拉格朗日插值)
题意 题目链接 Sol 想不到想不到.. 首先在不考虑每个人的真是成绩的情况下,设\(f[i][j]\)表示考虑了前\(i\)个人,有\(j\)个人被碾压的方案数 转移方程:\[f[i][j] = \ ...
- BZOJ4559 JLOI2016成绩比较(容斥原理+组合数学+斯特林数)
容斥一发改为计算至少碾压k人的情况数量,这样对于每门课就可以分开考虑再相乘了.剩下的问题是给出某人的排名和分数的值域,求方案数.枚举出现了几种不同的分数,再枚举被给出的人的分数排第几,算一个类似斯特林 ...
- bzoj千题计划270:bzoj4559: [JLoi2016]成绩比较(拉格朗日插值)
http://www.lydsy.com/JudgeOnline/problem.php?id=4559 f[i][j] 表示前i门课,有j个人没有被碾压的方案数 g[i] 表示第i门课,满足B神排名 ...
- 【bzoj4559】[JLoi2016]成绩比较(dp+拉格朗日插值)
bzoj 题意: 有\(n\)位同学,\(m\)门课. 一位同学在第\(i\)门课上面获得的分数上限为\(u_i\). 定义同学\(A\)碾压同学\(B\)为每一课\(A\)同学的成绩都不低于\(B\ ...
随机推荐
- C++自学第二课:对象和类的概念
既然是C++,比C语言多了最重要的概念:面向对象. 面向对象?对象是什么?Girlfriend? 我天天面向她也没学会C++. 我觉得对象就是有统一特征的一类编程目标. 打个比方说墙上有个开关,我一按 ...
- appium+python自动化☞appium python api大全
整理了一些常用的appium python api,供学习使用...
- selenium、unittest——POM框架并出报告
学习隔壁大神的POM框架,结合自己的用例进行修改整理并执行,操作遇到的主要问题是如何分布的写各个模块并统一运行,每个文件夹想要import里面的模块需要有__init__模块 POM主要分为三个部分, ...
- Unity编辑器扩展 Chapter3--Create Custom Inspector
一.Create Custom Inspector 重绘inspector面板一方面是我们的挂在脚本的窗口变得友好,另一方面可以让其变得更强大,比如添加一些有效性验证. 二.重要说明 1.Editor ...
- python程序设计——面向对象程序设计:继承
继承是为代码复用和设计复用而设计的 在继承关系中,已有的.设计好的类称为父类或基类,新设计的类为子类或派生类 派生类可以继承父类的公有成员,但不能继承其私有成员 如果需要在派生类中调用基类的方法,可以 ...
- CentOS7部署ELK5.2
原文发表于cu:2017-02-10 参考文档: Elasticsearchyum文档:https://www.elastic.co/guide/en/elasticsearch/reference/ ...
- openstack系列文章(三)
学习openstack的系列文章-glance glance 基本概念 glance 架构 openstack CLI Troubleshooting 1. glance 基本概念 在 opensta ...
- [CF1137]Museums Tour
link \(\text{Description:}\) 一个国家有 \(n\) 个城市,\(m\) 条有向道路组成.在这个国家一个星期有 \(d\) 天,每个城市有一个博物馆. 有个旅行团在城市 \ ...
- 十大经典排序算法总结 (Python)
作业部落:https://www.zybuluo.com/listenviolet/note/1399285 以上链接是自己在作业部落编辑的排序算法总结- Github: https://github ...
- SST:Single-Stream Temporal Action Proposals论文笔记
SST:Single-Stream Temporal Action Proposals 这是本仙女认认真真读完且把算法全部读懂(其实也不是非常懂)的第一篇论文 CVPR2017 一作 论文写作的动机m ...