ferinの競プロ帳

競プロについてのメモ

SRM625 div1 easy PalindromePermutations

解法

まず、回文が存在する条件として
* それぞれの文字種の個数が全て偶数
* 一つの文字種だけ奇数でそれ以外は偶数
のいずれかの条件を満たす必要がある。文字種ごとに文字列内の個数を数え、奇数のものが2個以上あれば存在しないので0を出力する。
cnt[i] = 文字種iの個数とすると、文字列を並べ替えるパターン数は (|S|!)/(cnt[0]!cnt[1]!cnt[25]!) となる。回文の数は (|S|/2)! / ((cnt[0]/2)!(cnt[0]/2)!(cnt[0]/2)!) なので計算すればできる。オーバーフローに注意。

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef vector<int> VI;
typedef vector<VI> VVI;
typedef vector<ll> VL;
typedef vector<VL> VVL;
typedef pair<int, int> PII;

#define FOR(i, a, n) for (ll i = (ll)a; i < (ll)n; ++i)
#define REP(i, n) FOR(i, 0, n)
#define ALL(x) x.begin(), x.end()
#define IN(a, b, x) (a<=x&&x<b)
#define MP make_pair
#define PB push_back
const int INF = (1LL<<30);
const ll LLINF = (1LL<<60);
const double PI = 3.14159265359;
const double EPS = 1e-12;
const int MOD = 1000000007;
//#define int ll

template <typename T> T &chmin(T &a, const T &b) { return a = min(a, b); }
template <typename T> T &chmax(T &a, const T &b) { return a = max(a, b); }

int dx[] = {0, 1, 0, -1}, dy[] = {1, 0, -1, 0};

int cnt[30];

class PalindromePermutations {
   public:
   double palindromeProbability(string word)
  {
    memset(cnt, 0, sizeof(cnt));
    for(char c: word) cnt[c-'a']++;
    bool ng = false;
    int sum = 0;
    REP(i, 26) {
      if(!ng && cnt[i]%2) ng = true;
      else if(ng && cnt[i]%2) return 0;
      sum += cnt[i];
    }
    double ret = 1;
    FOR(i, (sum/2)+1, sum+1) {
      ret /= i;
    }
    REP(i, 26) {
      FOR(j, cnt[i]/2+1, cnt[i]+1) {
        ret *= j;
      }
    }
    return ret;
  }
};