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

    BZOJ2425: [HAOI2010]计数

    Description

    你有一组非零数字(不一定唯一),你可以在其中插入任意个0,这样就可以产生无限个数。

    比如说给定{1,2},那么可以生成数字12,21,102,120,201,210,1002,1020,等等。

    现在给定一个数,问在这个数之前有多少个数。(注意这个数不会有前导0).

    Input

    只有1行,为1个整数n.

    Output

    只有整数,表示N之前出现的数的个数。

    Sample Input

    1020

    Sample Output

    7

    HINT

    n的长度不超过50,答案不超过263-1.


    题解Here!

    这题思路和数位$DP$差不多。

    一位一位向前推进。

    首先我们知道,对于一个数,把其中的$0$删掉,相当于把$0$放到了前面。

    所以这个问题就是让我们求一下给我们的数字的全排列中比当前小的有几个。

    设$num[i]$代表数字$i(iin[0,9])$有几个。

    那么全排列就是这个式子:
    $$frac{(sum_{i=0}^9num[i])!}{prod_{i=0}^9num[i]!}$$

    当然如果$num[i]==0$那么不参与运算。。。

    但是这样的话$long long$表示存不下。

    我已经说了我不会再写高精度的!

    所以继续想优化。

    假设现在有$m$个位置。

    我们先把$0$放法放好:
    $$C_m^{num[0]}$$

    之后就只有$m-num[0]$个位置。

    然后再放$1$:
    $$C_{m-num[0]}^{num[1]}$$

    以此类推。。。

    所以答案长这个样:
    $$Ans=C_m^{num[0]} imes C_{m-num[0]}^{num[1]} imes... imes C_{m-num[0]-num[1]-...-num[8]}^{num[9]}$$

    然后这个组合数就用杨辉三角什么的乱搞就好了。

    附代码:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #define MAXN 1010
    using namespace std;
    int n,val[MAXN],num[MAXN];
    long long triangle[MAXN][MAXN];
    inline void read(){
    	char c=0;
    	n=0;
    	while(c<'0'||c>'9')c=getchar();
    	while(c>='0'&&c<='9'){val[++n]=c-'0';num[val[n]]++;c=getchar();}
    }
    long long C(long long n,long long m){
    	if(triangle[n][m])return triangle[n][m];
    	if(m==1)return n;
    	if(m==0||m==n)return 1;
    	if(m>n)return 0;
    	triangle[n][m]=C(n-1,m)+C(n-1,m-1);
    	return triangle[n][m];
    }
    long long solve(int x){
        long long s=1;
        for(int i=0;i<=9;i++)
        if(num[i]){
            s*=C(x,num[i]);
            x-=num[i];
        }
        return s;
    }
    void work(){
    	long long ans=0;
    	for(int i=1;i<=n;i++){
    	    for(int j=0;j<val[i];j++)
            if(num[j]){
                num[j]--;
                ans+=solve(n-i);
                num[j]++;
            }
            num[val[i]]--;
        }
        printf("%lld
    ",ans);
    }
    int main(){
    	read();
    	work();
        return 0;
    }
    
  • 相关阅读:
    HTML5 完美解决javascript中iphone手机和android手机复制文本到剪切板问题
    去除移动端alert/confirm的网址(url)
    项目通过tomcat部署到服务器,请求数据中文乱码问题
    JEECG中表单提交的中断
    mysql数据库1129错误
    java中比较两个double类型值的大小
    spring配置上传文件大小
    GET方式,获取服务器文件
    java中多个数字运算后值不对(失真)处理方法
    V-rep学习笔记:关节力矩控制
  • 原文地址:https://www.cnblogs.com/Yangrui-Blog/p/9492835.html
Copyright © 2011-2022 走看看