【题目描述】 某一天,小????打开了一场????????????比赛,准备来一场爱的大训练。 这 场????????????比赛一共有????道题。 小????已经调查到自己能用???????? 毫秒来解决第????道题。 小????已经用过各种各样的开题姿势切了无数场????????????,这次他决定 使用一种新的姿势。 1.首先,小????将会随机的打开????道题。 2.小????会选择????道题中所需的时间最少的一道题并解决它。 3.如果还有没有打开的题目,小????会再随机的打开一道没打开过的 题。 4.若小????还没有解决所有的题目,则回到 2。 小????并不关注某种情况下的罚时,他只想知道在所有????!种情况下 自己的罚时总和。 定义一次比赛中的罚时为所有问题的被解决时刻之和,小????是个优 秀的代码 手所以他并不会产生其他的罚时。

【输入格式】 从文件 shit.in 中读入数据。 第一行二个整数????,K. 第二行????个整数描述????????。

【输出格式】 输出到文件 shit.out 中。 一行,输出答案对 109 + 7 取模的值。

【样例输入】

4 3 1 3 2 1

【样例输出】 336

【数据范围】 对于 10%的数据,???? ≤ 8。 对于 20%的数据,???? ≤ 15。 对于 30%的数据,???? ≤ 30。 对于 50%的数据,???? ≤ 100。 对于 100%的数据,???? ≤ 300,1 ≤ ???????? ≤ 1e6

 

sol:求数字i在前j位被取走的方案数,然后差分一下就是第i个数字在第j位被取走的方案了

标程有讲解

#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const int N=305,mo=1e9+7;
int n,m,k,i,x,j,a[N],la,ans;
int C[N][N],fact[N];
void init(){
    for (i=0;i<=n;i++) for (C[i][0]=1,j=1;j<=i;j++)
        C[i][j]=(C[i-1][j]+C[i-1][j-1])%mo;
    for (fact[0]=1,i=1;i<=n;i++)
        fact[i]=(ll)fact[i-1]*i%mo;
}
/*
    做第i轮时有i+k-1个数
    会取走前i小的数
    或者说前i小的数一定会被取走
    上式中
    m为当前第x轮的数个数
    当大于i的数个数大于等于m-x时
    i在前x小中
    得出的sum为i在前x轮被取走的情况数 
*/
int main(){
    freopen("shit.in","r",stdin);
    freopen("shit.out","w",stdout);
    scanf("%d%d",&n,&k);
    for (i=1;i<=n;i++) scanf("%d",&a[i]);
    sort(a+1,a+n+1);init();
    for (i=1;i<=n;i++) for (x=1,la=0;x<=n;x++){
        m=min(n,x+k-1);int sum=0;
        for (j=m-x;j<m;j++)
            sum=(sum+(ll)C[n-i][j]*C[i-1][m-1-j])%mo;
        sum=(ll)sum*fact[m]%mo*fact[n-m]%mo;
        ans=(ans+(ll)(sum-la+mo)*(n+1-x)*a[i])%mo;
        la=sum;
    }
    printf("%d",ans);
}
bs

相关文章: