codeforces 991 E. Bus Number (含重复元素的排列组合+dfs)

版权声明:本文为博主原创文章,转载请注明出处~~ https://blog.csdn.net/hxc2101/article/details/81984666

题目:http://codeforces.com/contest/991/problem/E

题意:有一串数,每个数都出现cnt[i]次 (为解释题意方便,这部分是需要自己计算一下的),对他进行排列组合,要求原数列中的每个数都需要出现>=1次,但不能超过cnt[i]次,且0不能放在开头,(在符合前面要求的前提下新数列长度是任意的),问这样的组合数。

思路:

1.计算每个数字的cnt[i] ;

2.dfs 并用 use[i] 记录每次新数列中该数出现的次数(排列组合的公式中要用到) (use[1] 从1到cnt[i]遍历) ;

3.对于数组中含重复元素的排列组合的种数的计算公式:\tfrac{A_{n}^{n}}{A_{a[0]}^{a[0]}*A_{a[1]}^{a[1]}*A_{a[2]}^{a[2]}*...*A_{a[n-1]}^{a[n-1]}}  (解释:分子表示总共有n个数进行全排列;分母中每一小部分表示每个数自己重复的次数进行全排列);

4.减去以0为开头的种数- \tfrac{A_{n-1}^{n-1}}{A_{(a[0]-1)}^{(a[0]-1)}*A_{a[1]}^{a[1]}*A_{a[2]}^{a[2]}*...*A_{a[n-1]}^{a[n-1]}} (解释:分子表示 第一个数放0,那么后面只有n-1个数能放了,对这n-1个数全排列;分母中不同的是 因为开头放了0 所以此时使用0的个数use[0]就是a[0]-1,其他的思路都和上式是相同的)

合起来就是: \tfrac{A_{n}^{n}}{A_{a[0]}^{a[0]}*A_{a[1]}^{a[1]}*A_{a[2]}^{a[2]}*...*A_{a[n-1]}^{a[n-1]}}- \tfrac{A_{n-1}^{n-1}}{A_{(a[0]-1)}^{(a[0]-1)}*A_{a[1]}^{a[1]}*A_{a[2]}^{a[2]}*...*A_{a[n-1]}^{a[n-1]}}

//阶乘的值 需要预处理    //注意数据开 long long 

#include <bits/stdc++.h>
#pragma GCC optimize(3)
//#pragma GCC optimize("unroll-loops")
//#pragma comment(linker, "/stack:200000000")
//#pragma GCC optimize("Ofast,no-stack-protector")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popans,abm,mmx,avx,tune=native")
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define pb push_back
#define mkp(a,b) make_pair(a,b)
#define PII pair<int,int>
#define PLL pair<ll,ll>
#define fi first
#define se second
#define lc (d<<1) //d*2
#define rc (d<<1|1) //d*2+1
#define eps 1e-9
#define dbg(x) cerr << #x << " = " << x << "\n";
#define mst(a,val) memset(a,val,sizeof(a))
#define stn(a) setprecision(a)//小数总有效位数
#define stfl setiosflags(ios::fixed)//点后位数:cout<<stfl<<stn(a);
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double PI=3.1415926535897932;
const int MAXN=1e5+10;
const ll mod=1e9+7;
ll inline mpow(ll a,ll b){ll ans=1;a%=mod;while(b){if(b&1)ans=(ans*a)%mod;a=(a*a)%mod,b>>=1;}return ans;}
int inline sgn(double x){return (x>-eps)-(x<eps);} //a<b:sgn(a-b)<0
priority_queue<int,vector<int>,greater<int> > qu; //up
priority_queue<int,vector<int>,less<int> > qd; //dn
const int inf = 0x3f3f3f3f; //9
const ll inff = 0x3f3f3f3f3f3f3f3f; //18

char s[50];
ll cnt[20];
ll use[20];
ll jc[20]; //阶乘的值 需要预处理
ll ans=0;  //注意数据开 long long

void dfs(ll x)
{
    if(x==10)
    {
        ll sum=0;
        for(ll i=0;i<=9;i++)  sum+=use[i];
        ll tmp=1;
        for(ll i=0;i<=9;i++)  tmp*=jc[use[i]];
        ans+=(jc[sum]/tmp);
        if(use[0]>=1) ans=ans-jc[sum-1]/(tmp/jc[use[0]]*jc[use[0]-1]);
        return;
    }
    for(ll i=1;i<=cnt[x];i++)  {use[x]=i;dfs(x+1);}
    if(cnt[x]==0) {use[x]=0;dfs(x+1);}
}

int main()
{
    fio;
    cin>>s;
    ll len=strlen(s);
    for(ll i=0;i<len;i++)
        cnt[s[i]-'0']++;
    jc[0]=1;
    for(ll i=1;i<=19;i++)
        jc[i]=jc[i-1]*i;
    dfs(0);
    cout<<ans<<endl;
}

猜你喜欢

转载自blog.csdn.net/hxc2101/article/details/81984666