码迷,mamicode.com
首页 > 其他好文 > 详细

UVa 153 - Permalex

时间:2015-04-02 10:29:31      阅读:180      评论:0      收藏:0      [点我收藏+]

标签:

题目:给你一个字符串,判断他是这些字符组成的全排列中按字典序排序的第几位。

分析:组合数学。康托展开,枚举长度求和即可。

            首先,考虑非重集,从前向后扫描,每一位找到前面相同本位小于对应值得串个数;

            例如:f(cba)= 2*2!+ 1*1!= 5,对应第6个串;

            (c**对应a、b开头的比他小,cb*对应ca开头的比他)

            然后,考虑重集,对应位置取相同的元素相同,剩余的元素要去掉相同的全排列;

            例如:f(cabaa)= (4!/3!+ 4!/2!)+ (0) + (2!/1!)+(0) = 18,对应第19个串;

            (c****对应b开头为4!/3!(aaa)、a开头为4!/2!(aa),cab**对应caa开头为2!/1!(a))

            注意,这里因为30!超过了long long,使用数组存所有的因数,利用gcd约分就得到int范围内的值了。

说明:还没有到600题╮(╯▽╰)╭。

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>

using namespace std;

int gcd(int a, int b)
{
	return a%b?gcd(b, a%b):b;
}

int main()
{
	int  letter[128];
	int  u[200],d[200];
	char buf[32];
	while (~scanf("%s",buf)) {
		if (!strcmp("#", buf)) 
			break;
		memset(letter, 0, sizeof(letter));
		for (int i = 0; buf[i]; ++ i)
			letter[buf[i]] ++;
		
		int len = strlen(buf),count = 1;
		for (int i = 0; i < len; ++ i) {
			int d_count = 0,u_count = 0;
			for (int j = 'a'; j <= 'z'; ++ j)
				for (int k = 2; k <= letter[j]; ++ k)
					d[d_count ++] = k;
			for (int k = 2; k <= len-1-i; ++ k)
				u[u_count ++] = k;
			
			for (int j = 'a'; j < buf[i]; ++ j) {
				if (letter[j]) {
					int g = 1,value = 1;
					
					u[u_count] = letter[j];
					for (int p = 0; p <= u_count; ++ p)
					for (int q = 0; q < d_count; ++ q) {
						g = gcd(u[p], d[q]);
						u[p] /= g;
						d[q] /= g;
					}
					for (int p = 0; p <= u_count; ++ p)
						value *= u[p];
					count += value;
				}
			}
			letter[buf[i]] --;
		}
		
		printf("%10d\n",count);
	}
    return 0;
}


UVa 153 - Permalex

标签:

原文地址:http://blog.csdn.net/mobius_strip/article/details/44827689

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!