排列组合计算-涉及到溢出与取模
公式
- 递归,使用 Cmn=Cmn−1+Cm−1n−1 C n m = C n − 1 m + C n − 1 m − 1 进行求解,这种方法在数据量很小时,会有效,但是在n很大时,效率很低,在这里
代码
typedef long long ll; int MOD = 1e9 + 7; ll getAcc(ll num, ll choose) { if (num == choose) return 1; if (choose == 1 ) return num; return (getAcc(num - 1, choose - 1) + getAcc(num-1, choose))%MOD; }
DP
- 建立m*n的数组,这样做就避免了递归时的迭代运算,经过优化,可以实现其空间复杂度为 O(N) O ( N ) ,但是N太大时,仍然不行(申请内存失败)
代码
typedef long long ll; const int MOD = 1e9 + 7; int getAcc_bkp(int n, int m) { if (n == m) return 0; if (m == 1) return n; m = min(m, n - m); bool curr = false; vector<vector<int>> data(2, vector<int>(n + 1, 0)); for (int i = 1; i <= n; i++) data[0][i] = 1; for (int i = 1; i <= m; ++i) { curr = !curr; data[curr][i] = 1; for (int j = i + 1; j <= n - m + i; ++j) //for (int j = i + 1; j <= n; j++) // 计算整个的 { data[curr][j] = (data[!curr][j - 1] + data[curr][j - 1]); if (data[curr][j] >= MOD) data[curr][j] -= MOD; } } return data[curr][n]; }
求解质因数
对m和n分别求因数分解,存在hashmap中,然后再进行计算,这种方法比之前的DP要快很多
代码
typedef long long ll; const int MOD = 1e9 + 7; void getMap(int n, unordered_map<int, int>& maps) { int curr = 2; while (true) { if (n == 1) break; if (n % curr == 0) { maps[curr]++; n = n / curr; } else { curr++; if (curr*curr > n) { maps[n]++; break; } } } } ll getAcc(int n, int m) { unordered_map<int, int> map_n; unordered_map<int, int> map_m; m = min( m, n-m ); for (int i = n-m+1; i <= n;++i) getMap( i, map_n ); for (int i = 2; i <= m; ++i) getMap(i, map_m); for (auto it = map_m.begin(); it != map_m.end(); ++it) { map_n[it->first] -= it->second; if (map_n[it->first] == 0) map_n.erase(it->first); } ll result = 1; for (auto it = map_n.begin(); it != map_n.end(); ++it) { for (int cnt = 0; cnt < it->second; ++cnt) result = (result * it->first) % MOD; } return result; }
注意
- 网上有很多方法是建立table进行求解,但是对于模很大的情况并不适用,个人建议还是因数分解最快最合适。
计蒜客比赛题解
题目链接
- https://nanti.jisuanke.com/t/27650
- 之前使用DP进行排列组合的计算,一直超时(2088ms>2000ms),使用因数分解的方法之后,瞬间解决(1455ms)。
代码
#include <cstdlib>
#include <string>
#include <iostream>
#include <fstream>
#include <vector>
#include <sstream>
#include <unordered_map>
#include <unordered_set>
#include <map>
#include <set>
#include <stdio.h>
#include <string.h>
#include <numeric>
#include <algorithm>
#include <functional>
using namespace std;
typedef long long ll;
const int MOD = 1e9 + 7;
int dirs[8][2] = { -1, -1, -1, 0, -1, 1, 0, -1, 0, 1, 1, -1, 1, 0, 1, 1 };
void getMap(int n, unordered_map<int, int>& maps)
{
int curr = 2;
while (true)
{
if (n == 1)
break;
if (n % curr == 0)
{
maps[curr]++;
n = n / curr;
}
else
{
curr++;
if (curr*curr > n)
{
maps[n]++;
break;
}
}
}
}
ll getAcc(int n, int m)
{
unordered_map<int, int> map_n;
unordered_map<int, int> map_m;
m = min( m, n-m );
for (int i = n-m+1; i <= n;++i)
getMap( i, map_n );
for (int i = 2; i <= m; ++i)
getMap(i, map_m);
for (auto it = map_m.begin(); it != map_m.end(); ++it)
{
map_n[it->first] -= it->second;
if (map_n[it->first] == 0)
map_n.erase(it->first);
}
ll result = 1;
for (auto it = map_n.begin(); it != map_n.end(); ++it)
{
for (int cnt = 0; cnt < it->second; ++cnt)
result = (result * it->first) % MOD;
}
return result;
}
void solve()
{
char s[100005] = { 0 };
char t[100005] = { 0 };
scanf("%s", s);
scanf("%s", t);
int len_s = strlen(s);
int len_t = strlen(t);
int tb[26] = { 0 };
for (int i = 0; i < len_s; ++i)
++tb[s[i] - 'a'];
for (int i = 0; i < len_t; ++i)
--tb[t[i] - 'a'];
bool match = true;
for (int i = 0; i < 26; i++)
{
if (tb[i] < 0)
{
match = false;
break;
}
}
if (!match)
{
printf("0\n");
return;
}
int num = len_s - len_t;
vector<int> vec;
for (int i = 0; i < 26; ++i)
{
if (tb[i] != 0)
vec.push_back(tb[i]);
}
ll result = 1;
if (!vec.empty())
{
for (int i = 0; i < vec.size() - 1; ++i)
{
result = (result * getAcc( num, vec[i] )) % MOD;
num -= vec[i];
}
}
result = (result * (len_s - len_t + 1)) % MOD;
printf("%lld\n", result);
}
int main(int /*argc*/, char** /*argv*/)
{
int T = 0;
scanf("%d", &T);
for (int i = 0; i < T; i++)
{
solve();
}
//system("pause");
return 0;
}