题解:[ARC148E] ≥ K
好题。
考虑我们将序列中本质相同的元素缩成一个,然后考虑计数。
我们将序列中的数分为两类,分别是 \(a_i < \frac{k}{2}\) 和 \(a_i \ge\frac{k}{2}\),之所以这么分是因为第一类数不能相邻,第二类数可以相邻,第一类数和第二类数之间有相邻的条件。
从大到小考虑第二类数,比如当前枚举到了 \(a_i\),把 \(<k-a_i\) 的第一类数加入序列中,因为这些第一类数和 \(a_i\) 不能相邻,并维护当前序列上的空位,一直做直到所有数都填到了序列里面。
记空位个数为 \(sum\),答案为 \(ans\),考虑加入一个数对答案和空位的贡献。
- 第一类数,它只能单独填到空位里面,并且会占据空位:
\[sum \leftarrow sum-cnt_{a_i},ans=ans\cdot \binom{sum}{cnt_{a_i}}
\]
- 第二类数,它可以填到任意空位,并且会增加空位:
\[sum \leftarrow sum+cnt_{a_i},ans=ans\cdot \binom{sum+cnt_{a_i}-1}{cnt_{a_i}-1}
\]
然后做完了,实现非常丑陋,写挂了和题解拍才拍出来。
复杂度 \(O(n \log n)\)。
代码实现
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod=998244353;
int binpow(int a,int b){
if(!b) return 1;
int res=binpow(a,b/2);
if(b&1) return res*res%mod*a%mod;
else return res*res%mod;
}
vector<int> v;
int n,k,a[200005],ans,sum,now,fac[200005];
map<int,int> cnt;
int C(int n,int m){
if(n<m) return 0;
if(n<0 || m<0){
if(n==m) return 1;
else return 0;
}
return fac[n]*binpow(fac[m],mod-2)%mod*binpow(fac[n-m],mod-2)%mod;
}
bool cmp(int x,int y){
return a[x]<a[y];
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>k;
fac[0]=1;
for(int i=1;i<=n;i++){
fac[i]=fac[i-1]*i%mod;
}
for(int i=1;i<=n;i++){
cin>>a[i];
if(!cnt[a[i]]) if(a[i]<(k+1)/2) v.push_back(i);
cnt[a[i]]++;
}
sort(v.begin(),v.end(),cmp);
ans=1,sum=1,now=0;
if(!cnt.size()){
cout<<0;
return 0;
}
for(auto it=prev(cnt.end());;it--){
if(it->first<(k+1)/2){
break;
}
while(now<v.size() && a[v[now]]+it->first<k){
ans=ans*C(sum,cnt[a[v[now]]])%mod;
sum-=cnt[a[v[now]]];
now++;
}
ans=ans*C(sum+it->second-1,sum-1)%mod;
sum+=it->second;
if(it==cnt.begin()) break;
}
while(now<v.size()){
ans=ans*C(sum,cnt[a[v[now]]])%mod;
sum-=cnt[a[v[now]]];
now++;
}
cout<<ans;
return 0;
}

浙公网安备 33010602011771号