●BZOJ 4559 [JLoi2016]成绩比较

题链:

http://www.lydsy.com/JudgeOnline/problem.php?id=4559

题解:

计数dp,拉格朗日插值法。
真的是神题啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊。


先来看看 dp定义:(由于每门课程的分数分布方案是独立的,所以先不管每科实际分数大小所贡献的方案数。)
dp[i][j]:表示前 i门课程,只考虑分数相对大小关系时,B神碾压了 j个人的方法数
也就是说上面的dp定义只是表示一个相对关系的方案数(即不考虑实际分数大小)。
那么dp的转移:
dp[i][k] += dp[i-1][j]*C(j,k)*C(N-j,N-R[i]-k)
含义呢:就是从在前i-1门课程中被碾压的 j 名同学中选出 k 个来继续碾压(即让他们该科分数任比B神低);同时在没有被碾压的 N-j个同学中选出N-R[i]-k个来使得他们的该科分数任比B神低。(使B神排在该门课程的第 R[i]名)

如果设 Y[i]表示第i门课程且B神排在第R[i]名时的分数分布方案数。

最后的答案就是 dp[N][k]*Y[1]*Y[2]*Y[3]*...*Y[M]

但是求这个 Y[i]就有点麻烦了,里面的 U[i]很大呀,根本不能跑循环去求和。
然后就要用到插值法了。 (不懂插值法?快点击这里,简单入门一波,很快的 ~)
再明确一下当前的目标: 某一门课程,总分为 U,B神排名为 R,求分数分布方案数。
令函数


则答案即为    P[U]。
不难发现,求和式的每一项的都不超过 XN-1,同时又最多只有 X项相加,
所以 P[X] 是最高次项的次数不超过 N 的多项式。
那么求出这个多项式,就只需要 N+1个点,就用插值法求出该函数了。
所以O(N2*logN(快速幂的log))的复杂度暴力求出前 N+1个点的函数值
(X1=1,P[1]) , (X2=2,P[2]) ...... (XN+1=N+1,P[N+1])
然后插值法得到函数 P[X]。
然后再 O(N2)的复杂度求出 X=U 时的函数值 P[U],即可得到当前科目的分数分布方案:Y[当前科目]。
又因为有 M 门科目,所以求 Y[]数组的总复杂度为 O(N3*logN)
erge的插值法代码:

ll Lagrange(ll U,ll R)
{
	static ll p[MAXN];
    for(int i=1;i<=n+1;i++){
        p[i]=0;
        for(int j=1;j<=i;j++)
            p[i]=(p[i]+Pow(j,n-R)*Pow(U-j,R-1))%Mod;
    }
    ll ret=0;
    for(int i=1;i<=n+1;i++){
        ll mul=1;
        for(int j=1;j<=n+1;j++)if(j!=i)
            mul=mul*(U-j+Mod)%Mod*inv[i-j+500]%Mod;
        mul=mul*p[i]%Mod;
        ret=(ret+mul)%Mod;
    }
    return (ret+Mod)%Mod;
}

复杂度有点高,但是可以AC。以下是优化。



这里就有一个比较绕的技巧。
因为对于 P[X]来说,不同的 X 取值既影响求和项的个数,又影响每一项的计算参数:


所以我们暴力求前N+1个点的函数值时不得不花费 O(N^2)的代价。
但注意到,我们这么求 P[X]函数是不是太亏了:花费这么高的复杂度却只需要用到 P[U]这一函数值。
所以优化如下,把 P[X] -> P‘[X]

注意到了变化么?

是的,我们把求和式的每一项里面的那个自变量 X 改为了一个常数 U。
这样就可以 O(N) 求出前 N+1个点的函数值 P‘[X]:
令:
那么 

显然是个前缀的形式,即 P‘[X]=P‘[X-1]+F[i]。(之前的 P[X]可没有这个性质哦)
求出了 P‘函数的 N+1个点后,就可以插值法求出 P‘[X],并得到 P‘[U]的值,返回答案就好了。
(在此,插值法也可以通过一个预处理前后缀积来做到 O(N)计算某一个函数值,这个就自己去看代码的实现了)



等等,不感觉有点不对么?
P‘函数有点不对呀,本来 P 函数还是好好的,结果把里面的自变量改变成了常数,怎么P‘还是对的?
的确, P‘函数几乎是错的。几乎对于所有的自变量 X,P[X]!=P‘[X]!
但是有一个 X‘是满足 P[X‘]=P‘[X‘],那个 X‘=U
也就是说 P[U]=P‘[U], 这个P‘函数只能在 X=U 时得到正确答案。
为什么呢,即我们把 P函数里面的每一项里的自变量 X变成了常数 U 后,
对于 X 取值不为 U时,显然 P[X]!=P‘[X]
可是当 X=U 时,就可以把那个已经看成常数U了的自变量X又看回为自变量,即两个函数此时的取值相同了。
换句话说我们构造了另外一个函数P‘,使得其函数图像与函数P的图像在 X=U时有交点。(我们牺牲了几乎所有的正确性,只保留了最有用的那部分,以此来提高效率。
吼吼,所以就这样了,求 Y[ ]的复杂度变为了O(N2*logN);
实现看看代码啦。

复杂度 O(N3)(DP部分)+O(N2*logN)(插值法部分)

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#define MAXN 150
#define _ %mod
#define filein(x) freopen(#x".in","r",stdin);
#define fileout(x) freopen(#x".out","w",stdout);
using namespace std;
const int mod=1000000007;
int dp[MAXN][MAXN],U[MAXN],R[MAXN],C[MAXN][MAXN],Y[MAXN],inv[MAXN];
int N,M,K,ANS;
int pow(int a,int b){
	int now=1;
	while(b){
		if(b&1) now=(1ll*now*a)_;
		a=(1ll*a*a)_; b>>=1;
	}
	return now;
}
int Lagrange(int u,int r){
	{
	/*	f(i) = ((i)^(N-R) + (U-i)^(R-1)) //级别最大项为 u^(N-1)
		p(x) = ∑|i=1,i<=x| ((i)^(R-N) + (U-i)^(R-1))
			 = ∑|i=1,i<=x| f(i)
		p(x) 级别最大项为 u*u^(N-1)=u^N,所以拉格朗日插值法求其多项式函数需要 N+1 个点
		返回的答案为 p(u)。*/
	}
	static int lpi[MAXN],rpi[MAXN],p[MAXN],ans,tmp;
	lpi[0]=1; rpi[N+2]=1; ans=0;
	for(int i=1;i<=N+1;i++){
		p[i]=(1ll*p[i-1]+1ll*pow(i,N-r)*pow(u-i,r-1)_)_;
		if(i==u) return p[i];
	}
	for(int i=1;i<=N+1;i++) lpi[i]=1ll*lpi[i-1]*(u-i)_;
	for(int i=N+1;i>=1;i--) rpi[i]=1ll*rpi[i+1]*(u-i)_;
	for(int i=1;tmp=1,i<=N+1;i++){
		tmp=1ll*tmp*lpi[i-1]_*rpi[i+1]_*inv[i-1]_*inv[N+1-i]_*p[i]_;
		tmp=(1ll*tmp*((N+1-i)&1?-1:1)+mod)_;
		ans=(1ll*ans+tmp)_;
	}
	return ans;
}
int main()
{
	scanf("%d%d%d",&N,&M,&K);
	inv[0]=1; inv[1]=1;
	for(int i=2;i<=N+1;i++) inv[i]=((-1ll*(mod/i)*inv[mod%i])_+mod)_;
	for(int i=1;i<=N+1;i++) inv[i]=1ll*inv[i]*inv[i-1]_;
	for(int i=1;i<=M;i++) scanf("%d",&U[i]);
	for(int i=1;i<=M;i++) scanf("%d",&R[i]);
	for(int i=0;i<=N;i++){
		C[i][0]=1;
		for(int j=1;j<=i;j++)
			C[i][j]=(1ll*C[i-1][j-1]+C[i-1][j])_;
	}
	for(int i=1;i<=M;i++) Y[i]=Lagrange(U[i],R[i]);
	dp[0][N-1]=1;
	for(int i=1;i<=M;i++)
		for(int j=0;j<=N-1;j++)
			for(int k=0;k<=min(j,N-R[i]);k++) if(N-1-j>=N-R[i]-k)
				dp[i][k]=(1ll*dp[i][k]+1ll*dp[i-1][j]*C[j][k]_*C[N-1-j][N-R[i]-k]_)_;
	ANS=dp[M][K];
	for(int i=1;i<=M;i++) ANS=1ll*ANS*Y[i]_;
	printf("%d",ANS);
	return 0;
}

时间: 2024-08-29 02:09:38

●BZOJ 4559 [JLoi2016]成绩比较的相关文章

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 还只会最简单的

4559[JLoi2016]成绩比较 容斥+拉格朗日插值法

4559: [JLoi2016]成绩比较 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 261  Solved: 165[Submit][Status][Discuss] Description G系共有n位同学,M门必修课.这N位同学的编号为0到N-1的整数,其中B神的编号为0号.这M门必修课编号为0到M- 1的整数.一位同学在必修课上可以获得的分数是1到Ui中的一个整数.如果在每门课上A获得的成绩均小于等于B获 得的成绩,则称A被B碾压.在B

【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千题计划270:bzoj4559: [JLoi2016]成绩比较

http://www.lydsy.com/JudgeOnline/problem.php?id=4559 f[i][j] 表示前i门课,有j个人没有被碾压的方案数 g[i] 表示第i门课,满足B神排名的分数安排方案数 g[i]的求法: 枚举B神这门课x分,则有n-Ri个人的分数<=x ,Ri-1个人的分数>x Ui 上限是1e9,但是g[i] 是一个关于Ui 的n次多项式,所以可以用拉格朗日插值法来求 递推 f[i][j]: 假设f[i-1][w] 转移到了f[i][j],j>=w 前i

【BZOJ4559】[JLoi2016]成绩比较 动态规划+容斥+组合数学

[BZOJ4559][JLoi2016]成绩比较 Description G系共有n位同学,M门必修课.这N位同学的编号为0到N-1的整数,其中B神的编号为0号.这M门必修课编号为0到M-1的整数.一位同学在必修课上可以获得的分数是1到Ui中的一个整数.如果在每门课上A获得的成绩均小于等于B获得的成绩,则称A被B碾压.在B神的说法中,G系共有K位同学被他碾压(不包括他自己),而其他N-K-1位同学则没有被他碾压.D神查到了B神每门必修课的排名.这里的排名是指:如果B神某门课的排名为R,则表示有且

bzoj4559 [JLOI2016]成绩比较 拉格朗日插值

题目描述 G系共有n位同学,M门必修课.这N位同学的编号为0到N-1的整数,其中B神的编号为0号.这M门必修课编号为0到M-1的整数.一位同学在必修课上可以获得的分数是1到Ui中的一个整数. 如果在每门课上A获得的成绩均小于等于B获得的成绩,则称A被B碾压.在B神的说法中,G系共有K位同学被他碾压(不包括他自己),而其他N-K-1位同学则没有被他碾压.D神查到了B神每门必修课的排名. 这里的排名是指:如果B神某门课的排名为R,则表示有且仅有R-1位同学这门课的分数大于B神的分数,有且仅有N-R位

【LuoguP3270】[JLOI2016] 成绩比较

题目链接 题目描述 G系共有n位同学,M门必修课.这N位同学的编号为0到N-1的整数,其中B神的编号为0号.这M门必修课编号为0到M-1的整数.一位同学在必修课上可以获得的分数是1到Ui中的一个整数. 如果在每门课上A获得的成绩均小于等于B获得的成绩,则称A被B碾压.在B神的说法中,G系共有K位同学被他碾压(不包括他自己),而其他N-K-1位同学则没有被他碾压.D神查到了B神每门必修课的排名. 这里的排名是指:如果B神某门课的排名为R,则表示有且仅有R-1位同学这门课的分数大于B神的分数,有且仅

[JLOI2016] 成绩比较

推石子 首先设\(d[i]=\sum_{t=1}^{U[i]}t^{n-R[i]}(U[i]-t)^{R[i]-1}\),即第\(i\)门课程分数的合法分布方案数: 然后设\(f[i,j]\)表示前\(i\)门课程中\(j\)个人被碾压的合法方案数,转移有: \[ \begin{aligned} &f[i,j]=d[i]\times\sum_{k=1}^n\pmatrix{k\\k-j}\pmatrix{n-k-1\\(R[i]-1)-(k-j)}f[i-1,k] &f[0,n-1]=1

bzoj4559: [JLoi2016]成绩比较

感谢丁爷爷教我做这个题的后半部分. 首先,运用一发容斥原理,求出所有人与B神每门课分数相对关系的不同方案数. 这个似乎大(wo)家(lan)都(de)会(hui)了(yi),我就不说了,详见代码里的f. 然后,我们就需要计算每门课每个人的分数的方案数.对于每一门课,我们分别计算,然后把它们乘起来. 方便起见,令总分为s,名次为rk. 设B神的分数为x,则方案数为x^(n-rk)*(s-x)^(rk-1) 展开得到c(rk-1,0)*s^(rk-1)*x^(n-rk)-c(rk-1,1)*s^(r