专栏文章
AT_abc431_f题解
AT_abc431_f题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @minazcdz
- 此快照首次捕获于
- 2025/12/01 23:27 3 个月前
- 此快照最后确认于
- 2025/12/01 23:27 3 个月前
不重要的碎碎念
为数不多的几次场切F题,虽然这题显然没有F题难度,但是还是很有纪念意义的
简要题目
给你一个长度为 的整数序列 和一个正整数 。
求通过重新排列 得到的满足以下条件的整数序列 的个数:
求通过重新排列 得到的满足以下条件的整数序列 的个数:
- 对所有 都成立。
结果对
998244353 取模。其中 。
分析
首先好想到数组的一开始的顺序对结果并无影响,不妨将原数组先排好序,接着从小往大往序列里加数。
我们假设现在已经排好序,加完前 个数了,思考能够把第 个数放在哪些位置。
其实就是两个条件(我们假设当前数为 ,放在了 的后面以及 的前面):
当且仅当上述两个条件成立时, 才能放在 与 之间。
由于我们是从小往大排序的,因此第一个条件一定成立。对于第二个条件,我们只需要维护在 前面的一共有多少个数 使得 成立,我们记为 ,这个其实是一段区间,左端点是单调的,因此可以双指针预处理。
不要忘了, 其实也可以加在最后的位置,因此在第 位的答案要乘以 。
最后还有一点细节,就是关于重复的问题,其实只需要处理一下每个数出现了多少次,写个阶乘的逆元处理一下就好啦。
放代码时间。
CPP#include<bits/stdc++.h>
#define int long long
#define For(i,a,b) for(int i=a;i<=b;i++)
#define Rof(i,a,b) for(int i=a;i>=b;i--)
#define fs first
#define sc second
#define pii pair<int,int>
#define pb push_back
using namespace std;
const int N=2e5+5,mod=998244353;
int n,d,a[N],pre[N],fac[N],inv[N];
int quickPow(int a,int b)
{
int ans=1;
while(b)
{
if(b&1)
ans=(ans*a)%mod;
b>>=1;
a=(a*a)%mod;
}
return ans;
}
void init()
{
fac[0]=1;
for(int i=1;i<N;i++)
{
fac[i]=fac[i-1]*i%mod;
}
inv[N-1]=quickPow(fac[N-1],mod-2);
for(int i=N-2;i>=0;i--)
{
inv[i]=inv[i+1]*(i+1)%mod;
}
}
void solve()
{
init();
cin>>n>>d;
For(i,1,n)cin>>a[i];
sort(a+1,a+n+1);
int now=0;
a[0]=-0x3f3f3f3f;
For(i,1,n)
{
while(now<i&&a[i]>a[now]+d)now++;
pre[i]=i-now;
// cout<<i<<' '<<a[i]<<' '<<pre[i]<<'\n';
}
// cout<<'\n';
int ans=1;
now=1;
// cout<<inv[1]<<'\n';
For(i,2,n)
{
if(a[i]!=a[i-1])
{
// cout<<now<<' '<<inv[now]<<' '<<ans<<'\n';
ans=ans*inv[now]%mod;
now=0;
}
now++;
}
ans=ans*inv[now]%mod;
For(i,1,n)
ans=ans*(pre[i]+1)%mod;
cout<<ans;
}
signed main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL),cout.tie(NULL);
int t=1;
// cin>>t;
while(t--)solve();
return 0;
}
后记
什么?这竟然是原。
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...