OI 笑传 #35
今天是 bct Day 5,摆烂日。
ylx 你之前在 mx 不是讲得很好来着吗。
T1
设 \(c_i\) 表示数字 \(i\) 在序列 \(a\) 中的出现次数,我们从前往后枚举,先计算再把数填进对应位置。
瞪眼可得位置 \(i\) 的答案为:
\[\sum_{j=1}^{a_i-1}\frac{(n-i)!}{c_1!c_2!\cdots (c_j-1)!c_{j+1}!\cdots}
\]
考虑一个很智慧的事情,我们把这些分式通分,也就是:
\[\sum_{j=1}^{a_i-1}\frac{(n-i)!c_j}{c_1!c_2!\cdots c_j!c_{j+1}!\cdots}
\]
于是可以化成:
\[\frac{(n-i)!\sum_{j=1}^{a_i-1}c_j}{c_1!c_2!\cdots c_j!c_{j+1}!\cdots}
\]
对每个位置支持单点修改前缀求和,树状数组即可。
枚举完每一位后,要把数填进去,也就是 \(c_{a_i}\) 减 \(1\),下面那一堆分母是很好维护的。
答案为这些分式的和。
1h10min 做完了就去摆烂了。
code
Show me the code
#define rd read()
#define mkp make_pair
#define ls p<<1
#define rs p<<1|1
#define rep(i,a,b) for( int i=(a); i<=(b); ++i)
#define per(i,a,b) for( int i=(a); i>=(b); --i)
#include<bits/stdc++.h>
using namespace std;
typedef long long i64;
typedef unsigned long long u64;
typedef unsigned int u32;
typedef __int128 i128;
i64 read(){
i64 x=0,f=1;
char c=getchar();
while(c>'9'||c<'0'){if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return x*f;
}
const int N=3e6+623452;
const int mod=998244353;
int tong[N];
int a[N];
i64 jc[N];
i64 inv[N];
int id,n,k;
i64 ksm(i64 a,i64 b){
i64 res=1,k=a;
while(b){
if(b&1){
res=res*k%mod;
}
k=k*k%mod;
b>>=1;
}
return res;
}
i64 c[N];
void add(int p,int k){
for(;p<=n;p+=((-p)&p))c[p]+=k;
return ;
}
void dec(int p){
for(;p<=n;p+=((-p)&p))c[p]--;
return ;
}
i64 que(int p){
i64 res=0;
for(;p>0;p-=(p&(-p))){
res=(res+c[p])%mod;
}
return res;
}
int main(){
freopen("sequence.in","r",stdin);
freopen("sequence.out","w",stdout);
cin>>id>>n>>k;
jc[0]=1;
i64 fenmu=1;
for(int i=1;i<=N-21123;i++){
jc[i]=jc[i-1]*i%mod;
inv[i]=ksm(i,mod-2);
}
for(int i=1;i<=n;i++){
a[i]=rd;
tong[a[i]]++;
}
for(int i=1;i<=k;i++){
fenmu=fenmu*jc[tong[i]]%mod;
add(i,tong[i]);
}
i64 ans=0;
for(int i=1;i<=n;i++){
i64 fenzi=jc[n-i];
fenzi=fenzi*que(a[i]-1)%mod;
ans=(ans+(fenzi*ksm(fenmu,mod-2)))%mod;
dec(a[i]);
fenmu=fenmu*ksm(jc[tong[a[i]]],mod-2)%mod;
tong[a[i]]--;
fenmu=fenmu*jc[tong[a[i]]]%mod;
}
cout<<(ans+1)%mod;
return 0;
}

浙公网安备 33010602011771号