[日常训练]挂科

Description

\(Y\)非常喜欢学习,但却又经常翘课,现在期末来临,他要挂科了。
期末考中小\(Y\)一共考了\(n\)门课,这\(n\)门课的分数为\(a_i\),而只要有一门课不及格,他就会留级。
现在小\(Y\)不知道每门课及格所要求的分数,他只知道他每一门课的分数都要严格高于这门课的要求分数。不过,小\(Y\)有个厉害的技能,那就是换成绩,具体地说,他可以将任意两门课的成绩互换,且他可以互换任意次。
现在他想知道,有多少种及格要求分数能不让他挂科(及格要求分数自然是非负整数)。
由于答案数可能很大,你只需要输出模\(10^9+7\)

Input

第一行一个整数\(T\),表示数据组数。
接下来\(T\)行每行一组数据。每组数据以一个整数\(n\)开头,表示课程数,后面\(n\)个整数\(a_i\)表示小\(Y\)\(n\)门课的成绩。

Output

\(T\)行,第\(i\)行表示第\(i\)组数据的答案。

Sample Input

4 
2 1 2 
3 2 5 3 
4 1 2 3 4 
4 9 8 3 5

Sample Output

3 
74 
125 
4371

HINT

\(1\;\leq\;n\;\leq\;1000,0\;\leq\;a_i\;\leq\;10^9,T\;\leq\;5\).

Solution

因为可以交换任意次,所以先将\(a_i\)从小到大排序.

\(f[i]\)表示处理到第\(i\)个数,前\(i\)个数合法的方案数.

\(f[i]=a_i^i-\sum_{j=1}^{i-1}(f[j-1]\;\times\;(a_i-a_j)^{i-j+1}\;\times\;C_i^{j-1})\).

即总方案数-不合法的方案数.

枚举\(j\),表示之前合法,在第\(j\)位不合法.之前合法的方案数为\(f[j-1]\)\(j\)位到第\(i\)位不合法,只能填\([a_j,a_i)\),这种情况在前\(i\)位一共有\(C_i^{j-1}\)种分布.

#include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 1005
#define P 1000000007
#define M 1000000007ll
using namespace std;
typedef long long ll;
ll fac[N],a[N],f[N],ans;
int n,t;
inline ll po(ll x,int k){
    ll ret=1ll;
    while(k){
        if(k&1) ret=ret*x%M;
        x=x*x%M;k>>=1;
    }
    return ret;
}
inline ll rev(ll x){
    if(x==1ll) return 1ll;
    ll ret=1ll;int k=P-2;
    while(k){
        if(k&1) ret=ret*x%M;
        x=x*x%M;k>>=1;
    }
    return ret;
}
inline ll c(int n,int m){
    return fac[n]*rev(fac[n-m])%M*rev(fac[m])%M;
}
inline void Aireen(){
    scanf("%d",&t);
    fac[0]=1ll;
    for(int i=1;i<=1000;++i)
        fac[i]=fac[i-1]*(ll)(i)%M;
    f[0]=1ll;
    while(t--){
        scanf("%d",&n);
        for(int i=1;i<=n;++i)
            scanf("%lld",&a[i]);
        sort(a+1,a+1+n);
        for(int i=1;i<=n;++i){
            f[i]=po(a[i],i);
            for(int j=1;j<i;++j)
                f[i]=(f[i]-f[j-1]*po(a[i]-a[j],i-j+1)%M*c(i,j-1)%M+M)%M;
        }
        printf("%lld\n",f[n]);
    }
}
int main(){
    freopen("godie.in","r",stdin);
    freopen("godie.out","w",stdout);
    Aireen();
    fclose(stdin);
    fclose(stdout);
    return 0;
}
posted @ 2017-01-10 13:11  Aireen_Ye  阅读(161)  评论(0编辑  收藏  举报
底部 顶部 留言板 归档 标签
Der Erfolg kommt nicht zu dir, du musst auf den Erfolg zugehen.