您的位置:首页 > 其它

bzoj4559【JLOI2016】成绩比较

2016-06-26 00:14 204 查看

4559: [JLoi2016]成绩比较

Time Limit: 20 Sec Memory Limit: 256 MB

Submit: 37 Solved: 29

[Submit][Status][Discuss]

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,则表示有且仅有R-1
位同学这门课的分数大于B神的分数,有且仅有N-R位同学这门课的分数小于等于B神(不包括他自己)。我们需要
求出全系所有同学每门必修课得分的情况数,使其既能满足B神的说法,也能符合D神查到的排名。这里两种情况不
同当且仅当有任意一位同学在任意一门课上获得的分数不同。你不需要像D神那么厉害,你只需要计算出情况数模1
0^9+7的余数就可以了。

Input

第一行包含三个正整数N,M,K,分别表示G系的同学数量(包括B神),必修课的数量和被B神碾压的同学数量。第二
行包含M个正整数,依次表示每门课的最高分Ui。第三行包含M个正整数,依次表示B神在每门课上的排名Ri。保证1
≤Ri≤N。数据保证至少有1种情况使得B神说的话成立。N<=100,M<=100,Ui<=10^9

Output

仅一行一个正整数,表示满足条件的情况数模10^9+7的余数。

Sample Input

3 2 1

2 2

1 2

Sample Output

10

容斥原理+组合数,思路好
wangyuzee的题解很棒,orz
整体思路:先求出所有其他人和B神每门课分数相对大小的不同方案数,然后再计算每门课的方案数,两者乘积即为答案。

① 先算第一部分,直接算比较难,考虑容斥原理。
f[i]表示有i个人被碾压的方案数,则f[i]=C(n-1,i)*C(n-1-i,rnk[1]-1)*C(n-1-i,rnk[2]-1)*…*C(n-1-i,rnk[m]-1)-f[i+1]*C(i+1,i)-f[i+2]*C(i+2,i)-…-f[n-1]*C(n-1,i),即用至少i个人被碾压的方案数减去不合法的。f数组逆向递推即可求出。

② 再算第二部分,对于每一门分别计算,然后乘起来。
假设某一门课的总分为s,B神的名次和分数分别为rnk和x,则方案数为x^(n-rnk)*(s-x)^(rnk-1)。
展开化简得∑ C(rnk-1,i)*s^(rnk-1-i)*x^(n-rnk+i),0≤i≤rnk-1。
我们要对x=1,2,…,s的所有情况求和。
把x次数相同的项放在一起,转化成求1^p+2^p+...+s^p,p为常数。
设g[i]=1^i+2^i+...+s^i,然后观察规律:
(s+1)^(p+1)-s^(p+1)=C(p+1,0)*s^0+C(p+1,1)*s^1+…+C(p+1,p)*s^p
s^(p+1)-(s-1)^(p+1)=C(p+1,0)*(s-1)^0+C(p+1,1)*(s-1)^1+…+C(p+1,p)*(s-1)^p
……
2^(p+1)-1^(p+1)=C(p+1,0)*1^0+C(p+1,1)*1^1+…+C(p+1,p)*1^p
将式子相加,得:(s+1)^(p+1)-1=C(p+1,0)*g[0]+C(p+1,1)*g[1]+…+C(p+1,p)*g[p]
移项,得:g[p]=((s+1)^(p+1)-1-C(p+1,0)*g[0]-C(p+1,1)*g[1]-…-C(p+1,p-1)*g[p-1]) / C(p+1,p)
于是可以通过正向递推求出g数组。

这样,这个问题就完美解决了,时间复杂度O(n^3)。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
#define N 105
#define mod 1000000007
using namespace std;
int n,m,k;
ll ans,s
,rnk
,fac
,inv
,f
,g
;
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;
}
inline ll getpow(ll x,ll y)
{
ll ret=1;
for(;y;y>>=1,x=x*x%mod) if (y&1) ret=ret*x%mod;
return ret;
}
inline ll C(int x,int y)
{
return fac[x]*inv[y]%mod*inv[x-y]%mod;
}
int main()
{
n=read();m=read();k=read();
F(i,1,m) s[i]=read();
F(i,1,m) rnk[i]=read();
fac[0]=inv[0]=1;
F(i,1,100) fac[i]=fac[i-1]*i%mod,inv[i]=getpow(fac[i],mod-2);
D(i,n-1,k)
{
f[i]=C(n-1,i);
F(j,1,m) f[i]=f[i]*C(n-1-i,rnk[j]-1)%mod;
F(j,i+1,n-1) f[i]=(f[i]-f[j]*C(j,i)%mod+mod)%mod;
}
ans=1;
F(i,1,m)
{
g[0]=s[i];
F(j,1,n)
{
g[j]=(getpow(s[i]+1,j+1)-1+mod)%mod;
F(l,0,j-1) g[j]=(g[j]-C(j+1,l)*g[l]%mod+mod)%mod;
g[j]=g[j]*getpow(j+1,mod-2)%mod;
}
ll tmp=0,p=1;
F(j,0,rnk[i]-1) tmp=(tmp+C(rnk[i]-1,j)*getpow(s[i],rnk[i]-1-j)%mod*g[n-rnk[i]+j]%mod*p+mod)%mod,p=-p;
ans=ans*tmp%mod;
}
cout<<ans*f[k]%mod<<endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: