1. 程式人生 > >Hdu-1261 字串數

Hdu-1261 字串數

Problem Description
一個A和兩個B一共可以組成三種字串:“ABB”,“BAB”,“BBA”.
給定若干字母和它們相應的個數,計算一共可以組成多少個不同的字串.

Input
每組測試資料分兩行,第一行為n(1<=n<=26),表示不同字母的個數,第二行為n個數A1,A2,…,An(1<=Ai<=12),表示每種字母的個數.測試資料以n=0為結束.

Output
對於每一組測試資料,輸出一個m,表示一共有多少種字串.

Sample Input
2
1 2
3
2 2 2
0

Sample Output
3
90

問題分析:
不難看出是有重複元素的排列問題。
sum = a1 + a2 + … + an;
公式 result = sum! / (a1 ! * a2 ! * … * an !);
但是,sum的最大值已經是300多了,肯定是高精度運算。
下面的程式碼:思路很簡單,先求出sum!再除a1到an的階乘。不過需要選擇適當的模板,ai的範圍是[1,12],所以除法的話用的是高精度除以單精度,是O(n)的演算法,乘法是自己寫的一個模板,複雜度是O(n^2), 下面的程式碼是AC的。

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;

typedef long long ll;



string mul(string a, string b)
{
	int len = a.size() + b.size();
	vector<int> res(len, 0);
	for (int i = 0; i < a.size(); i++)
	{
		for (int j =
0; j < b.size(); j++) { res[j + i] += (a[i] - '0') * (b[j] - '0'); } } string tmpres = ""; int i = res.size() - 2; int r = 0; while (i >= 0){ int t = res[i] + r; tmpres = (char)(t % 10 + '0') + tmpres; r = t / 10; i--; } while (r){ tmpres = (char)(r % 10 + '0') + tmpres; r = r /
10; } return tmpres; } string div(string a, ll b)//高精度a除以單精度b { string r, ans; ll d = 0; if (a == "0") return a;//特判 for (int i = 0; i<a.size(); i++) { r += (d * 10 + a[i] - '0') / b + '0';//求出商 d = (d * 10 + (a[i] - '0')) % b;//求出餘數 } ll p = 0; for (int i = 0; i<r.size(); i++) if (r[i] != '0') { p = i; break; } return r.substr(p); } ll get_n_i(int a) { ll res = 1; for (int i = 2; i <= a; i++) res *= i; return res; } int main() { int n; while (cin >> n, n) { vector<ll> nums(30); int m = 0; for (int i = 0; i < n; i++){ cin >> nums[i]; m += nums[i]; nums[i] = get_n_i(nums[i]); } string tmpa = "1"; for (int i = 2; i <= m; i++){ tmpa = mul(tmpa, to_string(i)); } for (int i = 0; i < n; i++){ tmpa = div(tmpa, nums[i]); } cout << tmpa << endl; } }