【一级讲解】不可思议唤来不可思议β——数学排列组合

不可思议唤来不可思议β

Time Limit: 1 Sec Memory Limit: 128 MB

Description

In the world line 1.048596%
双叶理央因为“青春期症候群”,分裂成为了两个人。由于被“冒牌货”顶替,“真正”的双叶理央只能借住在梓川咲太的家里。
“假设现在有一个设计图记录了一个人的所有信息,又因为量子隐形传态的原因在别的地方也出现了这样的设计图,那么就相当于存在了两个我。”
“但这毕竟不是理论能解释的事情,如果真的是量子隐形传态,那么我在行为的同时,也会影响另一个我。可现实并不是这样。”
“虽然很不想承认‘青春期症候群’的存在,不过如今也不得不承认了。”
“明明以前就那么不想承认?”梓川咲太坐在浴室的门前回应。
“实际上我还是不承认,这种非理性的事情。”,双叶理央叹了口气。
“双叶老师,其实前面我一句话都没听懂。”感觉到话题继续发展下去非常尴尬,梓川咲太开始自爆。
“没办法,抛开量子力学,用你这种笨蛋也能懂的话来说明吧。现在把人的所有特征信息简化为n个数字(0~9),那么自由组合成所有可能的n位数(包含前导零),然后这些数字再累加起来。这样的和就能代表那个人。”
“你就算这样说我也不是很懂啊…”
"假设梓川你的特征能简化为3个数字<0,1,2>,那么就能组成6个无视前导零的3位数,分别是012,021,102,120,210,201,这些数字加起来的和是666,那么666就能代表你这个人,kukuku,恶魔的数字,还真是不幸啊。”
“现在的我什么都不能反驳呢。”梓川不自觉的摸了摸胸前的伤痕。

然后,当晚被迫睡客厅的好男人梓川咲太总是睡不着。他一直在想如何快速的算出那个和。人脑始终是有极限的,那么只能求助于现代科技了。

Input

多组样例,每组输入包括两行;
第一行一个整数 n ,表示有n个数。(n<=10)
第二行包括 n 个整数x。(0 <= x <= 9)
当输入的 n 为 0 时结束输入(结束程序)
保证每组数据样例不超过50000个, 同时保证最后的答案不会超过2^63-1

Output

每组样例输出一行
每行一个数字,表示题目中要求的和

Sample Input

3 1 2 3 3 1 1 2 0

Sample Output

1332 444


问题分析:

不得不说这道题目我又陷入思维定势了,看到全排列,一想到的就是DFS,但DFS算法实际上展示出来的不是完整的一个个数,而是一个个单独的数位的拼接。再加上题目又要求要将这些数字相加,还要无视前导0,其实这两个条件用DFS算法稍微修改为加法还是可以解决的。但有一个很致命的问题就是,如何去除数据中重复计算的部分,我死活就想不出来用DFS这个要怎么解决这个问题。

想了许久无果后只能求助于论坛了,发现只有仅仅的一篇博客有讲解这道题目,看来是师兄了,看完之后如雷贯耳!很巧妙的用高中知识就解决了重复计算的问题,用排列组合的知识代替了DFS算法,这里我将师兄的博文内容复制过来给大家看看

排列组合题,显然枚举会超时。比赛时思路是对的,但是忘了含有重复元素的排列数怎么算,使劲推公式,没有思路,无果,,回来一查,这不是高中数学排列组合裸题吗!

假设有 111223这6个数,如何计算它的全排列呢?先假设这6个数字都不相同,排列共A(6,6)种,但在这A(6,6)种排列中,3个1和2个2是一样的,但被计算了A(3,3),A(2,2)种,因此答案就是A(6,6)/A(3,3)/A(2,2)种,这就是这道题最关键的地方。

先考虑最左边那一位可以填1,2,3三种,可以确定全排列中最高位分别为1,2,3时排列的个数,设排列总数为x,则最高位的数字可以确定加起来等于x105,其实全排列先考虑哪一个位都是一样的,其他每一位都可以这样考虑,结果就是x*105+x104+x*103+x10^2+x10+x.

这个x又怎么确定呢?当填1时排列数为1*(11223的全排列数),填2时排列数为2*(11123的全排列数),填3时排列数为3*(11122的全排列数),就是这样的思路。

下来写时候一处从0开始脑抽写出1开始,找不出错,然后花好多时间和next_permutation对拍才找出来错误。

不得不感慨,数学nb!师兄nb!

然后自己再写的时候,写完自己的代码再看师兄的代码,简直自愧不如,自己的代码质量太差了,太冗长了,可读性极差,师兄的代码真的超级精简,感觉像是一个艺术品!

强烈推荐大家看看师兄的其他博客


AC代码:

#include <bits/stdc++.h>
using namespace std;

int a[10];
int num[10];

//一开始闲的没事干还想用函数 多此一举
//int A(int n)
//{
//	if ( a[n] )
//		return a[n];
//	else
//		return a[n]=n*A(n-1);
//}

int main()
{
	int i,j;
	int t;
	while(1)
	{
		int n;
		cin >> n;
		
		if ( n==0 )
			break;
		
		long long ans=0;
		int type=0;
		long long sum=0;
		memset(num,0,sizeof(num));
		
		for ( i=0; i<n; ++i )
		{
			cin >> t;
			num[t]++;
		}
		
		a[0] = a[1] = 1;
		for ( i=2; i<=10; ++i )
			a[i] = i*a[i-1];
		
		for ( i=0; i<10; ++i )
			if ( num[i] )
			{
				sum = i*a[n-1];
				for ( j=0; j<10; ++j )
					if ( i==j )
						sum /= a[num[j]-1];
					else
						sum /= a[num[j]];
				type += sum;
			}
		
		for ( i=1; i<=n; ++i )
			ans = ans*10 + type;
			
		cout << ans << endl;
	}
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值