zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    关于在MAC上进行 LARAVEL 环境 Homestead 安装过程记录
    js 贷款计算器
    js 实现阶乘
    js 两点间距离函数
    composer Your requirements could not be resolved to an installable set of packages
    vue 项目优化记录 持续更新...
    vue 项目打包
    vue 真机调试页面出现空白
    vue 真机调试
    谈谈-Android状态栏的编辑
  • 原文地址:https://www.cnblogs.com/Leohh/p/8547392.html
Copyright © 2011-2022 走看看