3 aa aabb a
1 2 1
无语了,求杨辉三角居然忘了注意边界C(n, 0) = 1,求的时候取模还不彻底,无语......失之毫厘谬以千里......
思路主要就是判断字符串长度的奇偶性,结合每个元素的奇偶性来判断有没有可能组成回文
如果可以的话然后利用组合数来算有多少种
比如
cccbba a abbccc
len = 13 但是实际上只要算len / 2 = 6也就是黑体的这一半的组合情况就行了,另外一半对称
算法是,如果取a,b,c的顺序,那么对于a:C(6, 1),对于b去掉a占的位置:C(6 - 1, 2) = C(5, 2)
对于c去掉b, a占得位置:C(6 - 1 - 2, 3) = C(3, 3)
根据乘法原理ans = C(6, 1) * C(5, 2) * C(3, 3)
偶数情况以此类推
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <queue> #include <stack> #include <map> using namespace std; long long mod = 1000000007; char ch[1005]; long long c[1005][1005]; map<char, int> m; //用记忆化搜索来求杨辉三角,记忆数组c long long C(int n, int m) { if (n == m || m == 0) return 1; //注意边界 if (c[n][m] != -1) { return c[n][m] % mod; //注意取模 } return c[n][m] = (C(n - 1, m) + C(n - 1, m - 1)) % mod; //注意取模 } int main() { int T; //c是通用的直接放最外面就行 memset(c, -1, sizeof(c)); c[0][0] = 1; c[1][0] = 1; c[1][1] = 1; c[2][0] = 1; c[2][1] = 2; c[2][2] = 1; scanf("%d", &T); while (T--) { m.clear(); scanf("%s", ch); int len = strlen(ch); for (int i = 0; i < len; i++) { m[ch[i]]++; //散列计数,其实直接开个数组也行 } if (len == 1) { puts("1"); continue; } //算奇数的个数 int ji = 0; for (map<char, int>::iterator i = m.begin(); i != m.end(); i++) { if (i->second % 2) { ji++; } } long long ans = 1; //能算的情况是没有奇数,而且字符串的长度为偶数,或者有且仅有一个奇数字符串长度也为奇数 //否则不可能构成回文 if ((ji == 0 && len % 2 == 0) || (ji == 1 && len % 2 != 0)) { //只需要计算一般的情况就可以了,因为另外一般是对称的 len /= 2; for (map<char, int>::iterator i = m.begin(); i != m.end(); i++) { i->second /= 2; } for (map<char, int>::iterator i = m.begin(); i != m.end(); i++) { ans = (ans * (C(len, i->second) % mod)) % mod; //注意取模 len -= i->second; } } else { puts("0"); continue; } printf("%I64d\n", ans); } return 0; }