[JLoi2016]成绩比较

题解:

一道不错的题目

好像有容斥的方法。。我没看不知道

首先dp是比较简单的

f[i][j]表示考虑了前m门课,完全碾压了j个人

那么转移是

f[i][j]=sigma { f[i-1][k]*C(j,k)*C(n-j,a[i]-k) } *pi

时间复杂度n^3

其中pi表示选出他们分数的方案数

我们显然可以通过枚举我的得分来确定pi

pi=sigma {(maxn-x)^(rank[i]-1)*x^(n-rank[i])}

再下面就是看了别人题解才知道得。。

首先maxn非常大,所以暴力算一定是不可以的

上面的式子看上去比较复杂

将它写作 sigma{x,(k-x)^a*x^b}

将(k-x)^a用二项式定理展开

得到 C()*x^a*x^b+C()*k*x^a-1*x*b+.....

将每项拆开

得到C()*k^...*sigma{x,x^(a+b)}+......+......

现在的问题就在于维护自然数幂和了

由于模数是1e9+7

选择拉格朗日插值就可以了

代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define IL inline
#define rint register int
#define rep(i,h,t) for (rint i=h;i<=t;i++)
#define dep(i,t,h) for (rint i=t;i>=h;i--)
char ss[1<<24],*A=ss,*B=ss;
IL char gc()
{
  return A==B&&(B=(A=ss)+fread(ss,1,1<<24,stdin),A==B)?EOF:*A++; 
}
template<class T>IL void read(T &x)
{
  rint f=1,c; while (c=gc(),c<48||c>57) if (c=='-') f=-1; x=(c^48);
  while (c=gc(),c>47&&c<58) x=(x<<3)+(x<<1)+(c^48);  x*=f;
}
const int N=3e2+10;
const int mo=1e9+7;
const int INF=1e9;
int a[N],b[N],r[N],C[205][205],dp[N][N],f[N],jc[N];
int n,m,k;
IL void js(int &x,int y)
{
  x+=y;
  if (x>mo) x-=mo;
}
int qpow(int x,int y)
{
  if (y==0) return(1);
  if (y==1) return(x);
  int kk=qpow(x,y/2);
  kk=(1ll*kk*kk)%mo;
  if (y%2) kk=(1ll*kk*x)%mo;
  return(kk);
}
int query(int x,int k)
{
  rep(i,1,k+2) f[i]=(f[i-1]+qpow(i,k))%mo;
  if (x<=k+2) return(f[x]);
  jc[0]=1;
  rep(i,1,k+2) jc[i]=(1ll*jc[i-1]*i)%mo;
  int now=1,ans=0;
  rep(i,1,k+2) now=1ll*now*(x-i)%mo;
  rep(i,1,k+2)
  {
    int inv1=qpow(x-i,mo-2);
    int inv2=qpow(1ll*jc[i-1]*jc[k+2-i]%mo,mo-2);
    if ((k+2-i)%2) inv2=-inv2+mo;
    js(ans,1ll*inv1*inv2%mo*now%mo*f[i]%mo);
  }
  return(ans);
}
int main()
{
  freopen("1.in","r",stdin);
  freopen("1.out","w",stdout);
  read(n); read(m); read(k);
  rep(i,1,m) read(a[i]);
  rep(i,1,m) read(r[i]),b[i]=n-r[i];
  rep(i,0,200) C[i][0]=1;
  rep(i,1,200)
    rep(j,1,i)
      C[i][j]=(C[i-1][j]+C[i-1][j-1])%mo;
  dp[1][b[1]]=C[n-1][b[1]];
  rep(i,2,m)
    rep(j,k,b[i])
    {
      int tmp=0;
      rep(kk,j,n-1)
      {
        int tmp1=dp[i-1][kk];
        js(tmp,1ll*tmp1*C[kk][j]%mo*C[n-kk-1][b[i]-j]%mo);
      }
      dp[i][j]=tmp;
    }
  int ans=dp[m][k];
  rep(i,1,m)
  {
    rint kk=0;
    rep(j,0,r[i]-1)
    {
      int kk1=1ll*C[r[i]-1][j]*query(a[i],j+n-r[i])%mo*qpow(a[i],r[i]-1-j)%mo;
      if (j%2) kk1=-kk1+mo;
      js(kk,kk1);
    }
    ans=(1ll*ans*kk)%mo;
  }
  cout<<(ans+mo)%mo<<endl;
  return 0; 
}

 

posted @ 2018-07-28 14:54  尹吴潇  阅读(426)  评论(0编辑  收藏  举报