Maximum Palindromes

Sort by

recency

|

94 Discussions

|

  • + 0 comments

    The trick here is to use Fermat's little teorem for computing inverse factorials and precompute binomial coeffitiens modulo 10e9 + 7, then use them for computing the multinomial coeffitients for palindromes

  • + 1 comment

    My solution

    def _FACT_TABLE():
        facts=[0, 1, 2]
        def _fact(n):
            if n<len(facts)-1:
                return facts[n]
            for i in range(len(facts), n+1):
                facts.append(facts[i-1]*i)
            return facts[n]
        return _fact
    
    _fact=_FACT_TABLE()
    
    
    def _sort(symbs):
        p_s=[x//2 for x in symbs.values() if x//2 > 0 ]
        m_s=[x%2 for x in symbs.values() if x%2 > 0 ]
        return p_s, m_s
       
       
    def _to_symbs(l, r):
        symbs={}
        for i in range(l-1,r):
            symbs[S[i]]=symbs.get(S[i],0)+1
        return symbs
        
        
    def _calculate(p_s, m_s):
        res=_fact(max(sum(p_s), 1))
        for x in p_s:
            res=int(res/_fact(x))
        res=res*max(len(m_s),1)
        return res
        
        
    def answerQuery(l, r):
        # Return the answer for this query modulo 1000000007.
        symbs=_to_symbs(l,r)
        if len(symbs)==1:
            return 1
        p_s, m_s=_sort(symbs)
        return _calculate(p_s, m_s)
       
    
  • + 0 comments
    #include <cstdio>
    #include <cmath>
    #include <iostream>
    #include <set>
    #include <algorithm>
    #include <vector>
    #include <map>
    #include <cassert>
    #include <string>
    #include <cstring>
    #include <queue>
    
    using namespace std;
    
    #define rep(i,a,b) for(int i = a; i < b; i++)
    #define S(x) scanf("%d",&x)
    #define S2(x,y) scanf("%d%d",&x,&y)
    #define P(x) printf("%d\n",x)
    #define all(v) v.begin(),v.end()
    #define FF first
    #define SS second
    #define pb push_back
    #define mp make_pair
    
    typedef long long int LL;
    typedef pair<int, int > pii;
    typedef vector<int > vi;
    
    const int mod = 1000000007;
    const int N = 100005;
    
    LL F[N], IF[N];
    
    LL _pow(LL a, LL b) {
      if(!b) return 1;
      if(b == 1) return a;
      if(b == 2) return a * a % mod;
      if(b & 1) {
        return a * _pow(a,b-1) % mod;
      }
      return _pow(_pow(a,b/2),2);
    }
    
    void pre() {
      F[0] = 1;
      rep(i,1,N) {
        F[i] = i * F[i-1] % mod;
      }
      IF[N - 1] = _pow(F[N - 1], mod - 2);
      for(int i = N - 2; i >= 0; i--) {
        IF[i] = IF[i + 1] * (i + 1) % mod;
      }
    }
    
    int X[26][N];
    
    int main() {
      pre();
      string s;
      cin >> s;
      int n = s.size();
      rep(i,0,n) {
        rep(j,0,26) X[j][i+1] = X[j][i];
        X[s[i]-'a'][i+1]++;
      }
      int q;
      S(q);
      while(q--) {
        int l,r;
        S2(l,r);
        int tot = 0;
        LL ans = 1;
        int odd = 0;
        rep(i,0,26) {
          int x = X[i][r] - X[i][l-1];
          odd += (x&1);
          ans *= IF[x / 2];
          ans %= mod;
          tot += x / 2;
        }
        ans *= F[tot];
        ans %= mod;
        if(odd) ans = ans * odd % mod;
        printf("%lld\n",ans);
      }
      return 0;
    }
    
  • + 0 comments

    The only trick here is to cache the frequency map, since you are going to use it for every single test in the test-range. Do not bother caching modinverse, etc. The real cost is the string manipulation. Do something like this in your initialize function

      std::vector<std::vector<int>> s_cumulativeFreq;
    
      void initialize(std::string s)
      {
        std::vector<std::vector<int>>(s.size()+1, std::vector<int>(26, 0)).swap(s_cumulativeFreq);
        for (size_t i = 0; i < s.size(); ++i) {
          auto& prevFreq = s_cumulativeFreq[i];
          auto& currFreq = s_cumulativeFreq[i + 1];
          std::copy(prevFreq.begin(), prevFreq.end(), currFreq.begin());
          ++currFreq[s[i] - 'a'];
      }
     }
    

    And of course, calculate the difference in frequencies...

    int answerQuery(int first, int last)
    {
      auto len = last - first + 1;
      if (len == 1)
        return 1;
    
      std::vector<int> freqs = s_cumulativeFreq[last];  // Compute the frequencies in the range [l, r)
      {
        auto leftIter = next(s_cumulativeFreq.begin(), first - 1); // I want to remove the entries BEFORE 'first'
        transform(freqs.begin(), freqs.end(), leftIter->begin(), freqs.begin(), std::minus<int>()); // Compute the frequencies in the range [l, r]
      }
    
      auto middleChars = std::count_if(freqs.begin(), freqs.end(), [](int f) {return f & 1; });
      // Now I divide by 2. I only care about the left side of the palindrome
      for_each(freqs.begin(), freqs.end(), [](auto& f) {f >>= 1; });
      freqs.erase(std::remove(freqs.begin(), freqs.end(), 0), freqs.end());
      // Total number of chars to permutate...
      auto palindromeChars = accumulate(freqs.begin(), freqs.end(), 0, std::plus<int>());
      ...
      You can fill the rest
      ...
    
  • + 1 comment

    C++ (more at https://github.com/IhorVodko/Hackerrank_solutions , feel free to give a star : ) )
    These links are helpfull to unserstand the problem:
    https://blogarithms.github.io/articles/2019-01/fermats-theorem
    https://www.geeksforgeeks.org/multiplicative-inverse-under-modulo-m/

    const size_t MODULO = 1'000'000'007;
    auto factorials = std::vector<size_t>();
    auto modularMultiplicativeInverses = std::vector<size_t>();
    auto counts = std::vector<std::unordered_map<char, size_t>>();
    
    size_t findMdularMultiplicativeInverse(
        size_t const & _inverseOfThisNum,
        size_t const _power
    ){
        if(_power == 0){
            return 1;
        }
        auto  temp = 
            findMdularMultiplicativeInverse(_inverseOfThisNum, _power / 2) %
                 MODULO;
        temp = (temp * temp) % MODULO;
        return  ((_power % 2) == 0 ? temp : _inverseOfThisNum * temp) %
            MODULO;
    }
    
    void initialize(
        std::string const & _str
    ){
        factorials.resize(_str.size() / 2 + 1, 1);
        modularMultiplicativeInverses = factorials;
        counts.resize(_str.size() + 1);
        for(size_t indx = 2; indx != factorials.size(); ++indx){
            factorials.at(indx) = (indx * factorials.at(indx - 1)) % MODULO;
            modularMultiplicativeInverses.at(indx) = 
                findMdularMultiplicativeInverse(factorials.at(indx),
                    MODULO - 2);
        }
        for(size_t indx = 0; indx < _str.size(); ++indx){
            counts.at(indx + 1) = counts.at(indx);
            ++counts.at(indx + 1)[_str.at(indx)];
        }
    }
    
    int answerQuery(
        int const & _begin,
        int const & _end
    ){
        size_t maxLenthHalf = 0;
        size_t middleChar = 0;
        size_t denominator = 1;
        size_t countCurrent = 0;
        for(auto const & [chr, count]: counts.at(_end)){
            countCurrent = count - counts.at(_begin - 1)[chr];
            if(countCurrent >= 2){
                denominator = (denominator * 
                    modularMultiplicativeInverses.at(countCurrent / 2)) %
                        MODULO;
                maxLenthHalf += countCurrent / 2;
            }
            if(countCurrent % 2 == 1){
                ++middleChar;
            }
        }
        return (((factorials.at(maxLenthHalf) * denominator) % MODULO) *
            (middleChar == 0 ? 1 : middleChar)) % MODULO;
    }