AT_arc148_e ≥ K

原题链接

一种很新的思路。

考虑使得你放一个数的时候,要不然就是之后所有数都可以放在它旁边,要不然就是都不可以。

于是先排序,对于一个 \(<\dfrac{k}{2}\) 的数 \(a_i\),挂在第一个 \(\geq k-a_i\) 的位置上(本质或许是双指针,但我并不想这么说)。

然后从大到小放所有 \(\geq\dfrac{k}{2}\) 的数,放完一个数就把挂在它上面的数也放了,发现这样所有 \(\geq\dfrac{k}{2}\) 的数和 \(<\dfrac{k}{2}\) 的数分别满足最开始说的两种情况。

这样两种数放完以后会分别使得能放数的位置加一或减一,直接乘起来就完了。

最后除以每种数出现次数的阶乘来消去相同数的重复排列。

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<vector>
#define ll long long
using namespace std;
const int MAXN=2e5+10,mod=998244353;
int n,k,a[MAXN],cnt[MAXN];ll ans=1,T=1,P=1;
inline int ksm(ll a,int b=mod-2)
{
    ll ans=1;
    for(;b;b>>=1,a=a*a%mod)
        if(b&1) ans=ans*a%mod;
    return ans;
}
int main()
{
    // freopen("in.in","r",stdin);
    // freopen("out.out","w",stdout);
    cin.tie(0),cout.tie(0);
    ios::sync_with_stdio(0);
    cin>>n>>k;
    for(int i=1;i<=n;++i) cin>>a[i];
    sort(a+1,a+1+n);
    for(int i=1;i<=n&&a[i]<=(k-1)/2;++i)
    {
        if(a[n]+a[i]<k) cout<<"0\n",exit(0);
        ++cnt[lower_bound(a+1,a+n+1,k-a[i])-a];
    }
    for(int i=n;i&&a[i]>(k-1)/2;--i)
    {
        ans=ans*T%mod,++T;
        for(int j=1;j<=cnt[i];++j)
            ans=ans*T%mod,--T;
    }
    for(int i=1,j=1;i<=n;i=j)
    {
        while(a[j]==a[i]) ++j;
        for(int k=1;k<=j-i;++k)
            P=P*k%mod;
    }
    cout<<ans*ksm(P)%mod<<'\n';return 0;
}
posted @ 2024-07-29 15:18  int_R  阅读(112)  评论(5编辑  收藏  举报