题解:AT_arc148_e [ARC148E] ≥ K

· · 题解

求合法序列数量,考虑将所有数一个个插入;

由于需要维护可放的位置,所以我们要尽可能的让一个数被插入时,要么之后的数都能放在它的左右两边,要么都不能;

具体地,先对 a 数组排序,随后我们使用两个指针 lr,先固定 l,不断令 r \gets r-1 并插入 a_r 直到 a_l+a_r<k,随后插入 a_l 并令 $l \gets l+1

我们发现,当 $a_r$ 被插入序列中时,它的左右两边**一定可以放数**; - 因为当 $a_r$ 被插入时 $a_l+a_r \ge k$,而接下来的 $a_l$ 会变大,所以之后要插入的数都可以放在 $a_r$ 两侧。 而当 $a_l$ 被插入时,它的左右两边**一定不能放数**; - 当 $a_l$ 被插入时 $a_l+a_r<k$,而接下来 $a_r$ 会变小,所以之后要插入的数都不能放在 $a_l$ 两侧。 所以,每插入一个 $a_r$,会使可用位置增加 $1$;而每插入一个 $a_l$,会使可用位置减少 $1$,开一个 $tot$ 维护,每插入一个数时把当前的 $tot$ 乘到答案里即可。 注意此时我们将相同元素当成了不同元素计算,所以最后要除以每种数的个数的阶乘以消除影响。 ```cpp #include<bits/stdc++.h> #define int ll using namespace std; typedef long long ll; const int N=2e5+5; const int mod=998244353; int n,k,a[N]; int fac[N],inv[N]; int qp(ll a,int b,int mod=mod){ ll ans=1; while(b){ if(b&1)ans=ans*a%mod; b>>=1; a=a*a%mod; } return ans; } map<int,int> cnt; int ans=1; int tot=1; main(){ ios::sync_with_stdio(0); cin.tie(0);cout.tie(0); cin>>n>>k; fac[0]=inv[0]=1; for(int i=1;i<=n;i++)fac[i]=fac[i-1]*i%mod; inv[n]=qp(fac[n],mod-2); for(int i=n-1;i>=1;i--)inv[i]=inv[i+1]*(i+1)%mod; for(int i=1;i<=n;i++){ cin>>a[i]; cnt[a[i]]++; } sort(a+1,a+1+n); int l=1,r=n; while(l<=r){ ans=ans*tot%mod; if(a[l]+a[r]>=k)r--,tot++; else l++,tot--; } int tot=unique(a+1,a+1+n)-(a+1); for(int i=1;i<=tot;i++){ int tt=cnt[a[i]]; ans=ans*inv[tt]%mod; } cout<<ans; return 0; } ```