UVA 153 - Permalex

看了题解后才会的:

If you generate all  permutation of given string then you got TL, You can easily solve this problem using the formula : n! / (r1! * r2! * r3!...) Here n = total character, r1, r2, r3..= number of repeated character. Suppose aabbbc, n=6, r1=2, r2=3

Example:  
Input: dcaba

1. For string dcaba. Take the first character d, find all characters are less than d. Here the characters are a, b, c.
    For character a, you can find 24 possible arrangement. Because without a the string is: dcba so, 4! = 24.
    For character b, you can find 12 possible arrangement. Because without b the string is: dcaa so, 4! / 2! = 12.
    For character c, you can find 12 possible arrangement. Because without c the string is: daba so, 4! / 2! = 12.
Then remove the first character from  "dcaba". You got "caba".

2. For string caba. Take the first character c, find all characters are less than c. Here the characters are a, b.
    For character a, you can find 6 possible arrangement. Because without a the string is: cba so, 3! = 6.
    For character b, you can find 3 possible arrangement. Because without b the string is: caa so, 3! / 2! = 3.
Then remove the first character from "caba". You got "aba"

3. For string aba. Take the first character a, find all characters are less than a. Here no character found.
Then remove the first character from "aba". You got "ba"

4. For string ba. Take the first character b, find all character are less than b. Here the character is a.
    For character a, you can find 1 possible arrangement. Because without a the string is: b so, 1! = 1.
Remove the first character from "ba". You got "a".
Do not need to do anything for that. 

Total arrangement: 24 + 12 + 12 + 6 + 3 + 1 = 58
So, 58 possible arrangement before come "dcaba". "dcaba" is the 59th arrangement.

You can do this recursively.
转自:http://www.outsbook.com/uva/?page=latest_post&category=-1&id=153

计算阶乘的话必须约分,不然会溢出,30 !太大.

#include <iostream>
#include <memory.h>
#include <cstdio>
#include <map>
#include <string>
using namespace std;
#define MAX 50
long long permutaion_repeated(string & str,map<char,int> & m){
	int denominators[MAX]={0},index=0;
	map<char,int>::iterator it=m.begin();
	for (;it!=m.end();++it)
	{
		while (it->second)
		{
			denominators[index++]=it->second--;
		}
	}
	long long n=1,d=1;
	for (int i=1;i<=str.size();++i)
	{
		n*=i;
		if(index>0){
			d*=denominators[--index];
		}
		if(d!=1&&!(n%d)){
			n/=d;
			d=1;
		}
	}
	return n;
}
int main(){
	string str;
	while (cin>>str,str!="#")
	{
		long long ans=1;
		for (int i=0;i<str.size();++i)
		{
			map<char,int>m;
			for (int j=i+1;j<str.size();++j)
			{
				if(str[j]<str[i])m[str[j]]++;//统计小于str[i]的字符
			}
			map<char,int>::iterator it;
			for (it=m.begin();it!=m.end();++it)
			{
				int j;
				for (j=i+1;j<str.size()&&str[j]!=it->first;++j);
				string temp(str.begin()+i,str.end());
				temp.erase(temp.begin()+(j-i));
				map<char,int>mt;
				for (j=0;j<temp.size();++j)//统计各个字母出现的次数
				{
					mt[temp[j]]++;
				}
				ans+=permutaion_repeated(temp,mt);
			}
		}
		printf("%10lld\n",ans);
	}
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值