zoukankan      html  css  js  c++  java
  • 洛谷P2518 [HAOI2010]计数

    这个题可以默认有前导0,然后那些位数比输入数据小的数就可以被一起统计了。

    之后就从第一位开始往后面扫,对于每一位,看是否达到限制,没有的话剩下的数随便排列就行,那么此时我们需要解决的就是可重集的全排列问题;如果达到限制就继续考虑之后的一位。

    下面重点说下怎么解决可重集的全排列问题:

    (S={n_1*a_1,n_2*a_2,cdots,n_k*a_k})是由(n_1)(a_1),(n_2)(a_2),...(n_k)(a_k)组成的多重集。则S的全排列个数为:

    [frac{n!}{n_1!*n_2!*cdots*n_k!} ]

    这个式子可以等于:

    [C_n^{n_1}*C_{n-n_1}^{n_1+n_2}*cdots*C_{n-sum_{i-1}^{k-1}n_i}^{sum_{i=1}^{k}n_ui} ]

    因为最后数据保证答案不超过long long的范围,所以我们这样直接把答案计算出来就好了,就不用担心阶乘溢出了。

    代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 55;
    ll cnt[10];
    ll ans ;
    char s[N] ;
    ll C[N][N] ;
    int main() {
        scanf("%s", s + 1) ;
        int n = strlen(s + 1);
        for(int i = 1; i <= n; i++) cnt[s[i] - '0']++;
        C[0][0] = C[1][0] = C[1][1] = 1;
        for(int i = 2; i < N; i++) {
            C[i][0] = 1;
            for(int j = 1; j < N; j++)
                C[i][j] = C[i - 1][j - 1] + C[i - 1][j] ;
        }
        for(int i = 1; i <= n; i++) {
            for(int j = 0; j < s[i] - '0'; j++) {
                if(cnt[j] >= 1) {
                    ll res = 1;
                    cnt[j]--;
                    ll sum = n - i;
                    for(int k = 0; k <= 9; k++) res *= C[sum][sum - cnt[k]], sum -= cnt[k] ;
                    cnt[j]++;
                    ans += res;
                }
            }
            cnt[s[i] - '0']--;
        }
        cout << ans;
        return 0;
    }
    
    
  • 相关阅读:
    BZOJ1786[AHOI2008]Pair配对
    [Accepted][POJ1986]Tarjan求lca
    BZOJ1265[AHOI2006]斐波卡契的兔子
    POJ2631 树最长路径
    BZOJ1406[AHOI2007密码箱]
    POJ3129计算几何水题
    [AHOI2005]SHUFFLE题解
    三分法求极值模板
    File Download Using JavaScript
    云计算IDC服务
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/10877507.html
Copyright © 2011-2022 走看看