[CF991E] Bus Number 解题记录
题意简述
给定一个序列 A A A,求构成序列 B B B 的方案数。满足:
- B B B 中的数字在 A A A 中出现过。
- A A A 中数字在 B B B 中也出现过。
- 不含前导 0 0 0。
题目分析
考虑先不管第
3
3
3 条限制,如果当前有
s
u
m
sum
sum 个数字,每个数字
i
∈
[
0
,
9
]
i \in [0,9]
i∈[0,9] 出现了
a
i
a_i
ai 次,那么总排列数就是
s
u
m
!
∏
i
=
0
9
a
i
\frac{sum!}{\prod \limits ^9 _{i=0} a_i}
i=0∏9aisum!。
接下来考虑含前导
0
0
0 的情况。
由于一共有
s
u
m
sum
sum 个数字,其中
0
0
0 有
a
0
a_0
a0 个,那么
0
0
0 开头的排列数就占所有排列数
p
p
p 的
a
0
s
u
m
\frac{a_0}{sum}
suma0 个(对于
s
u
m
sum
sum 中每个数都有以它为开头的对应排列,那么以
0
0
0 开头的就有
a
0
a_0
a0 个),所以就需要从
p
p
p 中减去
p
×
a
0
s
u
m
p \times \frac{a_0}{sum}
p×suma0。
暴力搜索 B B B 中每个数有多少个就行。
AC Code
#include<bits/stdc++.h>
#define arrout(a,n) rep(i,1,n)std::cout<<a[i]<<" "
#define arrin(a,n) rep(i,1,n)a[i]=read()
#define rep(i,x,n) for(int i=x;i<=n;i++)
#define dep(i,x,n) for(int i=x;i>=n;i--)
#define erg(i,x) for(int i=head[x];i;i=e[i].nex)
#define dbg(x) std::cout<<#x<<":"<<x<<" "
#define mem(a,x) memset(a,x,sizeof a)
#define all(x) x.begin(),x.end()
#define arrall(a,n) a+1,a+1+n
#define PII std::pair<int,int>
#define m_p std::make_pair
#define u_b upper_bound
#define l_b lower_bound
#define p_b push_back
#define CD const double
#define CI const int
#define int long long
#define il inline
#define ss second
#define ff first
#define itn int
int read() {
char ch=getchar();
int r=0,w=1;
while(ch<'0'||ch>'9') w=ch=='-'?-1:w,ch=getchar();
while(ch>='0'&&ch<='9') r=r*10+ch-'0',ch=getchar();
return r*w;
}
CI N=25;
std::string s;
int ans,a[N],cnt[N],fac[N];
void dfs(int x){
if(x>9){
int sum=0;
rep(i,0,9){
sum+=a[i];
}
int p=fac[sum];
rep(i,0,9){
p/=fac[a[i]];
}
if(a[0]){
p-=p*a[0]/sum;
}
ans+=p;
return ;
}
rep(i,1,cnt[x]){
a[x]=i;
dfs(x+1);
}
if(!cnt[x]){
dfs(x+1);
}
}
signed main() {
std::cin>>s;
rep(i,0,s.size()-1) {
cnt[s[i]-'0']++;
}
fac[0]=1;
rep(i,1,20){
fac[i]=fac[i-1]*i;
}
dfs(0);
std::cout<<ans;
return 0;
}