题目链接
一道非常经典的数据结构辅助计数题.
题意
给定字符串 s s s和 t t t,将 s s s中的字母随意排列,求排列的字典序小于 t t t的方法由多少种.
题解
本题的字母有
2
×
1
0
5
2\times 10^5
2×105种,因此需要用到数据结构辅助.我们不妨来思考一下只有
26
26
26种字母时候的做法.
首先统计
s
s
s中每种字母的个数,然后开始对
t
t
t的第一位进行计算.可以发现,
s
s
s的第一位放置的情况只有
3
3
3种.其中
s
1
>
t
1
s_1>t_1
s1>t1的情况不合法直接忽略,而
s
1
=
t
1
s_1=t_1
s1=t1的情况需要进行后续计算,
s
1
<
t
1
s_1<t_1
s1<t1的情况,后面的所有字母都可以随意排列.因此合法的数量就是去掉这一位之后的排列总数.那么怎么计算呢?
可以知道,
s
s
s的全部排列总数为
n
!
∏
i
=
1
k
c
n
t
k
!
\frac{n!}{\prod_{i=1}^{k}cnt_k!}
∏i=1kcntk!n!
所以这一位确定小的排列方式总数为
(
n
−
1
)
!
∏
i
=
1
k
c
n
t
k
!
c
n
t
[
s
1
<
t
1
]
\frac{(n-1)!}{\prod_{i=1}^{k}cnt_k!}cnt[s_1<t_1]
∏i=1kcntk!(n−1)!cnt[s1<t1],其中左边带分数线那一部分称为排列基数
s
s
s.
重新调整下一位确定小的排列基数
s
s
s,做法就是先乘
n
−
1
n-1
n−1的逆元和
c
n
t
[
t
1
]
cnt[t_1]
cnt[t1],然后我们在
c
n
t
cnt
cnt数组中减掉
t
1
t_1
t1,如果减完之后
c
n
t
cnt
cnt数组的这一位小于
0
0
0,那说明接下来所有的排法都是确定小或者确定大的,那就不用算了,直接把循环
b
r
e
a
k
break
break掉就可以了.
那么最后的问题就是现在有这么多种字母,怎么对每一位求出
s
i
<
t
i
s_i<t_i
si<ti的选法数量.
明显用树状数组就可以了,因此本题就迎刃而解了,谢谢大家.
#include<bits/stdc++.h> //Ithea Myse Valgulious
namespace chtholly{
typedef long long ll;
#define re0 register int
#define rel register ll
#define rec register char
#define gc getchar
// #define gc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<23,stdin),p1==p2)?-1:*p1++)
#define pc putchar
#define p32 pc(' ')
#define pl puts("")
/*By Citrus*/
char buf[1<<23],*p1=buf,*p2=buf;
inline int read(){
int x=0,f=1;char c=gc();
for (;!isdigit(c);c=gc()) f^=c=='-';
for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
return f?x:-x;
}
template <typename mitsuha>
inline bool read(mitsuha &x){
x=0;int f=1;char c=gc();
for (;!isdigit(c)&&~c;c=gc()) f^=c=='-';
if (!~c) return 0;
for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
return x=f?x:-x,1;
}
template <typename mitsuha>
inline int write(mitsuha x){
if (!x) return 0&pc(48);
if (x<0) pc('-'),x=-x;
int bit[20],i,p=0;
for (;x;x/=10) bit[++p]=x%10;
for (i=p;i;--i) pc(bit[i]+48);
return 0;
}
inline char fuhao(){
char c=gc();
for (;isspace(c);c=gc());
return c;
}
}using namespace chtholly;
using namespace std;
namespace ran {
const unsigned k1=53,k2=109,mak=4294967295,mod=1e9+7;
typedef unsigned long long ull;
ull sa,sb,ct;
ull rnd() {
sa=(sa*k1+k2)%mod;
sb=(sb*k2+k1)%mod;
(ct*(ct+1)>>1&1)?sa^=sb^=sa^=sb:0,++ct>mod?ct-=mod:0;
return sa;
}
ull rndll() {
sa=(sa*k1+k2)&mak;
sb=(sb*k2+k1)&mak;
(ct*(ct+1)>>1&1)?sa^=sb^=sa^=sb:0,++ct>mod?ct-=mod:0;
return sa<<32|sb;
}
ull rnd(ull l,ull r) {
return rnd()%(r-l+1)+l;
}
ull rndll(ull l,ull r) {
return rndll()%(r-l+1)+l;
}
}
const int yuzu=2e5,mod=998244353;
typedef ll fuko[yuzu|10];
fuko jic={1},inv,a,b,c;
ll kasumi(ll a,ll b=mod-2) {
ll zw=1;
for (;b;b>>=1,a=a*a%mod) if (b&1) zw=zw*a%mod;
return zw;
}
struct _bit {
fuko g;
void add(int x,int v) {
for (;x<=yuzu;x+=x&-x) g[x]+=v;
}
ll query(int x) {
ll zw=0;
for (;x;x&=x-1) zw+=g[x];
return zw;
}
}zw;
int main() {
int i,n,m;
read(n),read(m);
for (i=1;i<=n;++i) jic[i]=jic[i-1]*i%mod;
inv[n]=kasumi(jic[n]);
for (i=n-1;~i;--i) inv[i]=inv[i+1]*(i+1)%mod;
for (i=1;i<=n;++i) a[i]=read(),++c[a[i]],zw.add(a[i],1);
for (i=1;i<=m;++i) b[i]=read();
ll s=jic[n-1],ans=0,t=n-1;
for (i=1;i<=yuzu;++i) c[i]?s=s*inv[c[i]]%mod:0;
for (i=1;i<=m;++i) {
ans=(ans+zw.query(b[i]-1)*s)%mod;
s=s*c[b[i]]%mod*kasumi(t)%mod;
--t,--c[b[i]],zw.add(b[i],-1);
if (c[b[i]]<0) break;
if (i==n&&i<m) {
ans=(ans+1)%mod;
break;
}
}
printf("%lld\n",ans);
}