贝壳找房计数比赛之排列组合计算

排列组合计算-涉及到溢出与取模

公式

  • 递归,使用 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 ) ,但是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;
    }

猜你喜欢

转载自blog.csdn.net/u012526003/article/details/80720722
今日推荐