xiaoxin juju needs help
2016-03-27 13:31
351 查看
题意: 给你一个字符串(a-z),可以任意更改任意字符串的位置,但是不能删去任何字符串,得到的字符串必须是回文的,问你一共有多少种可能?
解法: 首先分析问题,你会发现如果字符串长度为偶数的话,且有字母出现了奇数次的话就输出0;如果字符串长度为奇数的话就一定要有且只有一个字母出现的次数为奇数,否则也输出0;
再认真分析下题意,你会发现排除了上述产生的情况,其实字符串长度为奇数和偶数是一样的情况,因为如果是奇数有一个字母为奇数的就一定在排列的正中间。
如果对上述情况了解了那就是一道很简单的排列组合问题了,首先要将各个字母出现的次数减半,然后对减半后的字母进行全排列注意去除重复的字母,例如输入的是aaaabbbbcc,先减半得到aabbc,对aabbc进行全排列为A(5,5)/(A(2,2)*A(2,2)),我当时比赛的时候就是这样写的,万万没想到如果数据非常大的时候有取模操作的话就会出现问题。
赛后想到了一种方法就是先不计算结果,可以用1到len/2的数组每位赋值为序列号,然后在去除重复字母的时候也是用数组保存相乘的每一位数,然后将每一位与前面保存的数进行约分,而且一定不会出现分数,最后将1-len/2的数组每一位进行相乘并且取模就可以了!
代码如下:
解法: 首先分析问题,你会发现如果字符串长度为偶数的话,且有字母出现了奇数次的话就输出0;如果字符串长度为奇数的话就一定要有且只有一个字母出现的次数为奇数,否则也输出0;
再认真分析下题意,你会发现排除了上述产生的情况,其实字符串长度为奇数和偶数是一样的情况,因为如果是奇数有一个字母为奇数的就一定在排列的正中间。
如果对上述情况了解了那就是一道很简单的排列组合问题了,首先要将各个字母出现的次数减半,然后对减半后的字母进行全排列注意去除重复的字母,例如输入的是aaaabbbbcc,先减半得到aabbc,对aabbc进行全排列为A(5,5)/(A(2,2)*A(2,2)),我当时比赛的时候就是这样写的,万万没想到如果数据非常大的时候有取模操作的话就会出现问题。
赛后想到了一种方法就是先不计算结果,可以用1到len/2的数组每位赋值为序列号,然后在去除重复字母的时候也是用数组保存相乘的每一位数,然后将每一位与前面保存的数进行约分,而且一定不会出现分数,最后将1-len/2的数组每一位进行相乘并且取模就可以了!
代码如下:
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <map> using namespace std; #define LL long long #define N 1005 const LL MOD = 1000000007; char str ; int save ; LL res; map<char, int>m; void init(int n) { for(int i=1; i<=n; i++) save[i] = i; } int gcd(int n, int m) { return m==0 ? n : gcd(m, n%m); } int main() { //cout<<gcd(0,3)<<endl; int T, len, odd; cin>>T; while(T--) { res = 1; odd = 0; cin>>str; len = strlen(str); m.clear(); for(int i=0; i<len; i++) m[str[i]] ++; for(char i='a'; i<='z'; i++) if(m[i]%2) odd++; if(odd>1 || (odd == 1 && len%2==0)) cout<<0<<endl; else if(len%2 == 0) { int total = 0; for(char i='a'; i<='z'; i++) { m[i] = m[i] / 2; total += m[i]; } init(total); for(char i='a'; i<='z'; i++) { while(m[i]) { int mm = m[i]; for(int j=total; j>0; j--) { int tmp = gcd(save[j], m[i]); save[j] = save[j] / tmp; m[i] = m[i] / tmp; } m[i] = mm - 1; } } for(int i=total; i>0; i--) res = (res * save[i])%MOD; cout<<res<<endl; } else { int total = 0; for(char i='a'; i<='z'; i++) { m[i] = m[i] / 2; total += m[i]; } init(total); for(char i='a'; i<='z'; i++) { while(m[i]) { int mm = m[i]; for(int j=total; j>0; j--) { int tmp = gcd(save[j], m[i]); save[j] = save[j] / tmp; m[i] = m[i] / tmp; } m[i] = mm - 1; } } for(int i=total; i>0; i--) res = (res * save[i])%MOD; cout<<res<<endl; } } return 0; }
相关文章推荐
- C#查找字符串所有排列组合的方法
- js实现简单排列组合的方法
- PICT3.3用户指南学习笔记
- 数学符号,不常用的时候参考一下…
- 排列组合
- 变态组合数C(n,m)求解
- Next Permutation-Leetcode
- Codeforces Round #341 (Div. 2) CF621B. Wet Shark and Bishops(排列组合+对角线规律)
- [BZOJ1211][HNOI2004][prufer序列][排列]树的计数
- c++ The compile error : unresolved overloaded funciton type
- 任意数字序列“123456”之类,输出它们所有的排列组合
- 排列组合基本公式
- c# 全排列算法
- 组合数
- Java 一个关于魔兽世界5人小队的组合问题
- catalan数
- 排列组合算法
- bzoj 1801: [Ahoi2009] chess 中国象棋
- perl社工密码字典生成器
- 递归求排列组合-组合篇