[CF991E] Bus Number 解题记录

这篇文章讨论了解决编程竞赛题目的方法,涉及计算给定序列A中数字构成序列B的排列数,同时满足B中数字在A中出现且不含前导0的规则。作者使用了递归和组合数学的思想来求解,给出了C++代码实现。
摘要由CSDN通过智能技术生成

[CF991E] Bus Number 解题记录


题意简述

给定一个序列 A A A,求构成序列 B B B 的方案数。满足:

  1. B B B 中的数字在 A A A 中出现过。
  2. A A A 中数字在 B B B 中也出现过。
  3. 不含前导 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=09aisum!
接下来考虑含前导 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;
}
  • 28
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值