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

    II.[HAOI2010]计数

    我不得不吐槽出题人的语文实在太……那个了。

    翻译一下:给你一个数,求它是全排列中第几个。

    为什么呢?我们看一下给定的那个\(\{1,2\}\)的例子。显然,在任何合法的数中,所有的非零数的出现次数,在每个数中都是相同的。如果我们允许前导零,那么所有的\(0\)的出现次数也都相同了。(删去\(0\)可以看作将\(0\)移到了开头)

    我们考虑借鉴数位DP的思想:从高位向低位枚举,并考虑当前这位填入比原数小的数还是和原数相同的数。

    如果填入一个比它小的数,那么后面的位就可以全排列了。

    考虑每个数\(i\)共出现了\(cnt_i\)次,所有数总共出现了\(tot\)次。

    数字\(0\)可以在这\(tot\)个位置里面随便填,共\(C_{tot}^{cnt_0}\)种方案。

    数字\(1\)可以在剩下\(tot-cnt_0\)个位置里面随便填,共\(C_{tot-cnt_0}^{cnt_1}\)种方案。

    以此类推。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    int n,num[100],cnt[10],C[100][100],res;
    char s[100];
    int calc(int tot){
    	int ans=1;
    	for(int i=0;i<10;i++)ans*=C[tot][cnt[i]],tot-=cnt[i];
    	return ans;
    }
    signed main(){
    	scanf("%s",s+1),n=strlen(s+1);
    	for(int i=0;i<=n;i++)C[i][0]=1;
    	for(int i=1;i<=n;i++)for(int j=1;j<=i;j++)C[i][j]=C[i-1][j-1]+C[i-1][j];
    //	for(int i=0;i<=n;i++){for(int j=0;j<=i;j++)printf("%d ",C[i][j]);puts("");}
    	for(int i=1;i<=n;i++)num[i]=s[i]-'0',cnt[num[i]]++;
    	for(int i=1;i<=n;i++){
    		for(int j=0;j<num[i];j++){
    			if(!cnt[j])continue;
    			cnt[j]--;
    			res+=calc(n-i);
    			cnt[j]++;
    		}
    		cnt[num[i]]--;
    	}
    	printf("%lld\n",res);
    	return 0;
    }
    

  • 相关阅读:
    求一些数字字符参数的和(Java)
    《大道至简》第二章 读后感
    华为机试题 简单错误记录
    华为机试 购物单
    华为机试题 提取不重复的整数
    华为机试题 合并表结构
    华为机试 取近似值
    华为机试题 质数因子
    华为机试题 进制转换
    华为机试题 字符串分割
  • 原文地址:https://www.cnblogs.com/Troverld/p/14596761.html
Copyright © 2011-2022 走看看