洛谷P5684 非回文串 题解

题目链接:https://www.luogu.com.cn/problem/P5684

一开始有点错误的想法

首先判断字符串 \(s\) 能否组成回文串,

判断方法是开一个 \(cnt[]\) 数组,\(cnt[0]\) 用于记录字符 '\(a\)' 出现的次数,\(cnt[1]\) 用于记录字符 '\(b\)' 出现的次数,……,\(cnt[25]\) 用于记录字符 '\(z\)' 出现的次数。

然后,如果 \(cnt[0]\)\(cnt[25]\) 中奇数的个数大于 \(1\) ,那么 \(s\) 没有办法构成回文串。

此时可以得到非回文串的数量为 \(A_{n}^{n} = n!\)

如果可以构成回文串,那么我们需要计算一下有多少方案是可以构成回文串的:

可以考虑字符串的前半子串(前长度为 \(\lfloor \frac{n}{2} \rfloor\) 的子串)的构成,肯定是:

  • 选了 \(\lfloor \frac{cnt[0]}{2} \rfloor\) 个字符 'a';
  • 选了 \(\lfloor \frac{cnt[1]}{2} \rfloor\) 个字符 'b';
  • ……
  • 选了 \(\lfloor \frac{cnt[25]}{2} \rfloor\) 个字符 'z'。

然后答案应该是这前面 \(\lfloor \frac{n}{2} \rfloor\) 个元素的排列数 \(\lfloor \frac{n}{2} \rfloor !\) ,乘以字符 '\(a\)' 的排列数 \(cnt[0] !\),乘以 …… ,乘以字符 \(z\) 的排列数 \(cnt[25] !\)

所以此时答案应该是

\[n! - \lfloor \frac{n}{2} \rfloor ! \times \prod_{i=0}^{25} cnt[i] ! \]

修改后正确的想法

其实一开始左半边的排列已经确定了任意一个字符对应的排列了。

也就是我多算了 \(\lfloor \frac{cnt[i]}{2} \rfloor\) 的重复排列。

所以答案应该是

\[n! - \lfloor \frac{n}{2} \rfloor ! \times \prod_{i=0}^{25} \frac{cnt[i]!}{\lfloor \frac{cnt[i]}{2} \rfloor !} \]

实现代码如下:

#include <bits/stdc++.h>
using namespace std;
const long long MOD = 1000000007LL;
const int maxn = 2020;
long long f[maxn];
int n, cnt[26];
string s;

typedef long long ll;
void gcd(ll a , ll b , ll &d , ll &x , ll &y) {
    if(!b) {d = a; x = 1; y = 0;}
    else { gcd(b , a%b,d,y , x); y -= x * (a/b); }
}
ll inv(ll a , ll n) {
    ll d , x , y;
    gcd(a , n , d,  x , y);
    return d == 1 ? (x+n)%n : -1;
}

void init() {
    f[0] = 1;
    for (int i = 1; i < maxn; i ++) f[i] = f[i-1] * i % MOD;
}
int main() {
    init();
    cin >> n >> s;
    for (int i = 0; i < n; i ++) cnt[s[i] - 'a'] ++;
    int cc = 0;
    for (int i = 0; i < 26; i ++) if (cnt[i]%2) cc ++;
    if (cc > 1) cout << f[n] << endl;
    else {
        long long res = f[n/2];
        for (int i = 0; i < 26; i ++) {
            res = res * f[cnt[i]] % MOD;
            res = res * inv(f[cnt[i]/2], MOD) % MOD;
        }
        res = (f[n] - res + MOD) % MOD;
        cout << res << endl;
    }
    return 0;
}
posted @ 2020-03-02 16:22  quanjun  阅读(545)  评论(0编辑  收藏  举报