7.13 T2 Shit 题(shit)
【题目描述】 某一天,小𝐶打开了一场𝐴𝐶𝑀比赛,准备来一场爱的大训练。 这 场𝐴𝐶𝑀比赛一共有𝑁道题。 小𝐶已经调查到自己能用𝑇𝑖 毫秒来解决第𝑖道题。 小𝐶已经用过各种各样的开题姿势切了无数场𝐴𝐶𝑀,这次他决定 使用一种新的姿势。 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); }
#include <bits/stdc++.h> using namespace std; typedef long long ll; inline ll read() { ll s=0; bool f=0; char ch=' '; while(!isdigit(ch)) { f|=(ch=='-'); ch=getchar(); } while(isdigit(ch)) { s=(s<<3)+(s<<1)+(ch^48); ch=getchar(); } return (f)?(-s):(s); } #define R(x) x=read() inline void write(ll x) { if(x<0) { putchar('-'); x=-x; } if(x<10) { putchar(x+'0'); return; } write(x/10); putchar((x%10)+'0'); return; } #define W(x) write(x),putchar(' ') #define Wl(x) write(x),putchar('\n') const int N=305; const ll Mod=1000000007; ll n,m; ll fac[N],C[N][N]; ll t[N]; inline void Ad(ll &x,ll y) {x+=y; x-=(x>=Mod)?Mod:0;} int main() { freopen("shit.in","r",stdin); freopen("shit.out","w",stdout); ll i,j,k,Las,ans=0; R(n); R(m); for(i=1;i<=n;i++) R(t[i]); fac[0]=1; for(i=1;i<=n;i++) fac[i]=fac[i-1]*i%Mod; for(i=0;i<=n;i++) {C[i][0]=1; for(j=1;j<=i;j++) C[i][j]=(C[i-1][j]+C[i-1][j-1])%Mod;} sort(t+1,t+n+1); for(i=1;i<=n;i++) for(j=1,Las=0;j<=n;j++) //第i个数字第j轮 { ll cnt=min(n,m+j-1),Sum=0; for(k=cnt-j;k<cnt;k++)//有k个数字比第i个大 { Ad(Sum,C[n-i][k]*C[i-1][cnt-k-1]%Mod); } Sum=Sum*fac[cnt]%Mod*fac[n-cnt]%Mod;//Sum是第i个数在前j轮被取走的方案数 Ad(ans,1ll*(Sum-Las+Mod)*(n-j+1)%Mod*t[i]%Mod);//差分一下就是第i个第j轮被取走的,第j~n个要多等t[i]分钟 Las=Sum; } Wl(ans); return 0; } /* input 4 3 1 3 2 1 output 336 */
河田は河田、赤木は赤木……。
私は誰ですか。教えてください、私は誰ですか。
そうだ、俺はあきらめない男、三井寿だ!