zoukankan      html  css  js  c++  java
  • luogu2518 [HAOI2010] 计数

    题目大意

     给出一个数字$n$,求满足下列条件的数$x$的个数:

    1. $x<n$
    2. 对于来自于$x$十进制各个数位上的非零数字,它们的种类与个数都与$n$的相同。

    思路

    入手点

      设$n$有$t$位数字,如果满足上述条件的$x$的位数$t'$比$t$小,那相当于$x$前面含有$t-t'$个前缀0!因此如果我们不考虑第1条,那么$x$就是由$n$各个位上数字包括0组成的全排列。

    考虑第一条

      我们定义$a_i$为数$n$在第$i$位上的数字,$b_i$则是$x$的。$f(m)$为当$n$与$x$在$m$以上的位数都相等的情况下,满足题目条件的排列个数。若$a_m=b_m$,则转化为子问题$f(m-1)$;如果$b_m<a_m$,则$x$位数比$m$小的那部分无论如何排列,都会满足第一条,故结果为:对于每一个$b_min[0,a_m)$,将其锁定在第$m$位,$n$在$m$及以下的位数的所有数字排除掉被安在第一位的$b_m$后,在$m-1$个数中的全排列。由加法原理,这些结果都要相加

    怎么求含可重元素的全排列

      已知一个数组,$h_i$表示一个元素的个数,在长度$m$的区间里求它的全排列。其相当于先在区间中安0,共有$C_m^{h_0}$种选法;然后再在剩余的空间$m-h_0$中看看1的安放方式,即$C_{m-h_0}^{h_1}$。以此类推。根据乘法原理,这些组合数要相乘才为结果

    注意事项

    • ans用long long!
    • 求组合数递归时不要忘了给C数组赋值!
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <stack>
    #include <cstdlib>
    #include <iostream>
    using namespace std;
    
    #define ll long long
    const int MAX_DIGIT = 55, MAX_NUM = 10;
    ll A[MAX_DIGIT];
    int NumCnt[MAX_NUM];
    ll C[MAX_DIGIT][MAX_DIGIT];
    
    ll Comb(int n, int m)
    {
    	if (n < 0 || m < 0)
    		return 0;
    	if (C[n][m])
    		return C[n][m];
    	else if (m == 0 || m == n)
    		return C[n][m] = 1;
    	else if (m == 1)
    		return C[n][m] = n;
    	else if (m > n)
    		return 0;
    	else
    		return C[n][m] = Comb(n - 1, m - 1) + Comb(n - 1, m);
    }
    
    ll GetAns(const int len)
    {
    	if (len == 1)
    		return 0;
    	ll ans = 0;
    	for (int firstNum = 0; firstNum < A[len]; firstNum++)
    	{
    		NumCnt[firstNum]--;
    		int subLen = len - 1;
    		ll combAns = 1;
    		for (int num = 0; num < 10; num++)
    		{
    			combAns *= Comb(subLen, NumCnt[num]);
    			subLen -= NumCnt[num];
    		}
    		NumCnt[firstNum]++;
    		ans += combAns;
    	}
    	NumCnt[A[len]]--;
    	ans += GetAns(len - 1);
    	return ans;
    }
    
    int main()
    {
    	stack<int> st;
    	char c;
    	while (cin >> c && isdigit(c))
    		st.push(c - '0');
    	int len = 0;
    	while (!st.empty())
    	{
    		A[++len] = st.top();
    		NumCnt[A[len]]++;
    		st.pop();
    	}
    	cout << GetAns(len) << endl;
    	return 0;
    }
    

      

  • 相关阅读:
    第四章 数组和方法
    JAVA基础笔记
    ios navigationcontroller add multi navigationItem
    Objective-C Runtime能做什么?
    在Xcode中使用Git进行源码版本控制
    分析iOS Crash文件:符号化iOS Crash文件的3种方法
    Core Animation Layer(22)
    Touch Events and UIResponder(19)
    UIPopoverController and Modal View Controllers(13)
    Subclassing UITableViewCell(15)
  • 原文地址:https://www.cnblogs.com/headboy2002/p/9147797.html
Copyright © 2011-2022 走看看