列表

详情


NC211544. 火柴排队

描述

金发少女 DK 出了一套比赛,众所周知 DK 并不是一个好出题人,这回他的数据造的太烂了,有一道字符串题被“先搜长串再搜短串”的奇怪算法草了过去,导致有可能有一部分选手的实际分数比他的估分高了 d 分

DK 惊奇地发现,每个人的实际排名和他估分的排名完全一致,他觉得这种事情简直太少见了。假设从 n 位选手中选 k 位增加 d 分的 种方案的概率均相等,DK 希望你告诉他每个选手排名不变的概率。答案模 998244353

形式化地说:给出 n 个正整数 a_i,即每个选手的估分和 d,随机使 k 个元素增加 d( 种可能发生的概率相等),求增加后的序列 a'_i 满足如果 那么 的概率

对于每个 ,你都要输出其对应的答案。答案模 998244353

具体来说,所求的概率应该是一个有理数 ,你要输出的是满足 的 x。保证这个方程有解

输入描述

一行两个整数 n,d

接下来一行 n 个整数 a_i

输出描述

输出 n 行每行一个整数,第 i 行的整数表示 k=i 时的答案

示例1

输入:

5 2
3 4 7 9 8

输出:

199648871
898419918
898419918
199648871
1

说明:

当 k=1 时,共有5种可能
其中,给 a_2 或 a_4 加 d,满足条件
故概率为 \frac{2}{5},在 mod 998244353 意义下为 199648871

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 52ms, 内存消耗: 648K, 提交时间: 2020-09-12 00:16:41

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int M=5e3+5,mod=998244353;
int n,d,a[M];
ll dp[2][M],fac[M],inv[M];
int main()
{
    scanf("%d%d",&n,&d);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    sort(a+1,a+1+n);
    fac[0]=1;
    for(int i=1;i<=n;i++)fac[i]=fac[i-1]*i%mod;
    inv[0]=inv[1]=1;
    for(int i=2;i<=n;i++)inv[i]=(mod-mod/i)*inv[mod%i]%mod;
    for(int i=1;i<=n;i++)inv[i]=inv[i-1]*inv[i]%mod;
    int now=0;
    dp[0][0]=1;
    for(int l=1,r;l<=n;l=r+1)
    {
        now^=1;
        for(int i=0;i<=n;i++)dp[now][i]=dp[now^1][i];
        r=l;
        while(r<n&&a[r+1]<=a[r]+d)r++;
        for(int i=l;i<=r;i++)
            for(int j=r-i+1;j<=n;j++)
                dp[now][j]=(dp[now][j]+dp[now^1][j-r+i-1])%mod;
    }
    for(int i=1;i<=n;i++)printf("%lld\n",dp[now][i]*fac[i]%mod*fac[n-i]%mod*inv[n]%mod);
    return 0;
}

C++11(clang++ 3.9) 解法, 执行用时: 121ms, 内存消耗: 67648K, 提交时间: 2020-09-11 19:33:16

#include<bits/stdc++.h>
using namespace std;
const int mod=998244353;
int n,d;
int a[5050],f[5050],g[5050],C[5050][5050];
inline int qpow(int x,int k,int r=1){
	for(;k;k>>=1,x=1ll*x*x%mod) if(k&1) r=1ll*r*x%mod;
	return r;
}
int main(){
	cin>>n>>d;
	for(int i=1;i<=n;++i) cin>>a[i];
	sort(a+1,a+n+1); a[n+1]=(int)2e9+1; f[0]=1;
	for(int l=1,r=l;l<=n;l=++r){
		while(a[r]+d>=a[r+1]) ++r;
		memset(g,0,sizeof(g));
		for(int j=0;j<=n;++j){
			for(int k=0;k<=r-l+1;++k){
				(g[j+k]+=f[j])%=mod;
			}
		}
		memcpy(f,g,sizeof(f));
	}
	for(int i=0;i<=n;++i) for(int j=C[i][0]=1;j<=i;++j) C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
	for(int i=1;i<=n;++i) printf("%d\n",1ll*f[i]*qpow(C[n][i],mod-2)%mod);
	return 0;
} 

上一题