• BZOJ 2425 [HAOI2010]计数:数位dp + 组合数


    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2425

    题意:

      给你一个数字n,长度不超过50。

      你可以将这个数字:

        (1)去掉若干个0

        (2)打乱后重新排列

      问你可以产生多少个小于n的数字。

    题解:

      题目中的第一个操作其实是没有用的。

      去掉若干个0之后再重新排列(不允许前导0),和不去0直接重新排列(允许前导0),其实是等价的。

      所以按照数位dp的方法从高到低按位统计。

      如n = 2345时,分别统计前缀为0~1, 20~22, 230~233, 2340~2344的答案。

      最高位为第1位。

      假设当前考虑到第i位,1~i-1位都和原数字n完全匹配。

      枚举第i位可以填了x∈[0,a[i]),则先让cnt[x]--。

      然后就是i+1位之后的数如何填了。

      设len = n-i。

      方案数 = 先从len个位置中找了cnt[0]个位置全填0的方案数 * 又从(len-cnt[0])个位置中找了cnt[1]个位置全填1的方案数...

      方案数 = C(len,cnt[0]) * C(len-cnt[0],cnt[1]) * C(len-cnt[0]-cnt[1],cnt[2])...

      最后再让cnt[x]++回来,然后cnt[a[i]]--就好了。

    AC Code:

     1 #include <iostream>
     2 #include <stdio.h>
     3 #include <string.h>
     4 #define MAX_N 55
     5 #define MAX_D 15
     6 
     7 using namespace std;
     8 
     9 int n;
    10 long long ans=0;
    11 long long a[MAX_N];
    12 long long cnt[MAX_N];
    13 long long c[MAX_N][MAX_N];
    14 char s[MAX_N];
    15 
    16 void read()
    17 {
    18     scanf("%s",s+1);
    19     n=strlen(s+1);
    20     for(int i=1;i<=n;i++) cnt[a[i]=s[i]-'0']++;
    21 }
    22 
    23 void cal_c()
    24 {
    25     c[0][0]=1;
    26     for(int i=1;i<=n;i++)
    27     {
    28         c[i][0]=1;
    29         for(int j=1;j<=i;j++)
    30         {
    31             c[i][j]=c[i-1][j]+c[i-1][j-1];
    32         }
    33     }
    34 }
    35 
    36 long long cal_p(int len)
    37 {
    38     long long now=1;
    39     for(int i=0;i<=9;i++)
    40     {
    41         now*=c[len][cnt[i]];
    42         len-=cnt[i];
    43     }
    44     return now;
    45 }
    46 
    47 void cal_ans()
    48 {
    49     for(int i=1;i<=n;i++)
    50     {
    51         for(int j=0;j<a[i];j++)
    52         {
    53             cnt[j]--;
    54             ans+=cal_p(n-i);
    55             cnt[j]++;
    56         }
    57         cnt[a[i]]--;
    58     }
    59 }
    60 
    61 void work()
    62 {
    63     cal_c();
    64     cal_ans();
    65     printf("%lld
    ",ans);
    66 }
    67 
    68 int main()
    69 {
    70     read();
    71     work();
    72 }
  • 相关阅读:
    注册和登录与数据库内的链接
    数据访问
    马厩分配问题
    Codeforces Round #365 (Div. 2) D.Mishka and Interesting sum
    最优比例生成树模板
    01分数规划模板
    hiho一下第109周《Tower Defense Game》
    begin.BZOJ 1383: 三取方格数
    最小生成树
    Codeforces Round #364 (Div. 1)B. Connecting Universities
  • 原文地址:https://www.cnblogs.com/Leohh/p/8547392.html
Copyright © 2020-2023  润新知