【题目描述】 某一天,小????打开了一场????????????比赛,准备来一场爱的大训练。 这 场????????????比赛一共有????道题。 小????已经调查到自己能用???????? 毫秒来解决第????道题。 小????已经用过各种各样的开题姿势切了无数场????????????,这次他决定 使用一种新的姿势。 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); }