[JLOI2016]成绩比较
题目描述
G 系共有
如果在每门课上 A 获得的成绩均小于等于 B 获得的成绩,则称 A 被 B 碾压。在 B 神的说法中,G 系共有
这里的排名是指:如果 B 神某门课的排名为
我们需要求出全系所有同学每门必修课得分的情况数,使其既能满足 B 神的说法,也能符合 D 神查到的排名。这里两种情况不同当且仅当有任意一位同学在任意一门课上获得的分数不同。
你不需要像 D 神那么厉害,你只需要计算出情况数模
思路点拨
这篇题解是
这道题目我们可以把答案算成三个部分。我们一个个讲:
第一部分
我们需要选出
第二部分
我们除了B神以外的学术的相对成绩,具体的说,就是每一个学生的成绩是在B神之上还是之下。其实这一点并不麻烦,但是烦人的是,题目要求被B神吊打的学生 恰好 只有
我们可以定义
这
第三部分
我们需要给每一个学生分配分数。但是这个分数很大(怎么处理我们后面会讲到)
我们知道,对于每一个学科,成绩不超过B神的学生是有
直接求会超时,并且超的很多。但是看到这种式子我们要引起警觉。
如何获取答案
乘法原理,将三个部分的答案乘起来就可以了。这样子我们的时间复杂度就是每一个部分的时间复杂度
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-f;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
const int MAXN=1e2+10;
const int mod=1e9+7;
int qpow(int a,int b){
int ans=1,base=a;
while(b){
if(b&1) ans=ans*base%mod;
base=base*base%mod;
b>>=1;
}
return ans;
}
namespace Cmath{
int sum[MAXN],inv[MAXN];
void prepare(){
sum[0]=inv[0]=1;
for(int i=1;i<MAXN;i++){
sum[i]=sum[i-1]*i%mod;
inv[i]=qpow(sum[i],mod-2);
}
}
int C(int n,int m){
if(m>n||m<0) return 0;
return sum[n]*inv[m]%mod*inv[n-m]%mod;
}
int A(int n,int m){
return sum[n]*inv[n-m]%mod;
}
}
using namespace Cmath;
namespace Lagrange{
int pre[MAXN],suc[MAXN];
int lagrange(int *x,int *y,int n,int k){
int ans=0;
pre[0]=suc[n+1]=1;
for(int i=1;i<=n;i++) pre[i]=pre[i-1]*(k-x[i]+mod)%mod;
for(int i=n;i;i--) suc[i]=suc[i+1]*(k-x[i]+mod)%mod;
for(int i=1;i<=n;i++){
int top=pre[i-1]*suc[i+1]%mod;
int down=sum[x[i]-x[1]]*sum[x[n]-x[i]]%mod;
if((n-i)&1) down=(-down+mod)%mod;
ans=(ans+top*qpow(down,mod-2)%mod*y[i])%mod;
}
return ans;
}
}
using namespace Lagrange;
int n,m,k;
int U[MAXN],r[MAXN];
int x[MAXN],y[MAXN];
int fun(int p){
int ans=1;
for(int i=1;i<=m;i++)
ans=ans*C(p,r[i]-1)%mod;
return ans;
}
int run(int id){
for(int i=1;i<=n+1;i++){
x[i]=i;
y[i]=(y[i-1]+qpow(i,n-r[id])*qpow(U[id]-i,r[id]-1))%mod;
}
return lagrange(x,y,n+1,U[id]);
}
signed 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]=read();
Cmath:prepare();
int ans=0;
for(int i=0;i<=n-k-1;i++){
int cnt=(qpow(-1,n-k-1-i)+mod)*C(n-k-1,i)%mod*fun(i)%mod;
ans=(ans+cnt)%mod;
}
ans=ans*C(n-1,k)%mod;
for(int i=1;i<=m;i++) ans=ans*run(i)%mod;
cout<<ans<<endl;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现