专栏文章
[AT_abc431_f] [ABC431F] Almost Sorted 2 题解
AT_abc431_f题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @min83k2w
- 此快照首次捕获于
- 2025/12/01 22:06 3 个月前
- 此快照最后确认于
- 2025/12/01 22:06 3 个月前
条件就是在说,前一项最多比后一项大 。
考虑从大到小地填数。设当前填到数值 , 表示序列中有多少个 ,那么这些数只能插到当前序列的头部,或者满足 的 后方。设 即 的前缀和,则可以插入的空数量为 。
下面分析插入的方案数怎么计算。第一个被插入的 有 种方案,第二个在此基础上可以选择插入到第一个后方,有 种方案,以此类推。由于每个 完全相同,而前面却对 钦定了顺序,所以最后还要除以 。推知方案数为 。
最终答案如下。
计算组合数,设 ,可以先求出 表示 的阶乘,然后费马小定理求出 。然后递推 ,于是 。
code
CPP#include<bits/stdc++.h>
#define pb emplace_back
#define mp make_pair
using namespace std;
typedef long long ll;
const ll maxn=1000007,p=998244353;
ll n,D,c[maxn],s[maxn],ans,frac[maxn],inv[maxn];
ll qpow(ll a,ll b){ll E=1; for(;b;b>>=1,a=a*a%p)if(b&1) E=E*a%p; return E;}
void init(void){
frac[0]=1;
for(ll i=1;i<maxn;i++) frac[i]=frac[i-1]*i%p;
inv[maxn-1]=qpow(frac[maxn-1],p-2);
for(ll i=maxn-1;i>=1;i--) inv[i-1]=inv[i]*i%p;
}
ll C(ll a,ll b){return (a<b||b<0)?0:frac[a]*inv[b]%p*inv[a-b]%p;}
int main(void){
//freopen("data.in","r",stdin);
//freopen("data.out","w",stdout);
ios::sync_with_stdio(0),cin.tie(0);
cin>>n>>D,init();
for(ll i=1,x;i<=n;i++) cin>>x,c[x]++;
for(ll i=1;i<maxn;i++) s[i]=s[i-1]+c[i];
ans=1;
for(ll i=maxn-1;i>=1;i--)if(c[i]) ans=ans*C(s[min(maxn-1,i+D)]-s[i-1],c[i])%p;
cout<<ans<<"\n";
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...