zoukankan      html  css  js  c++  java
  • 洛谷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} floor) 的子串)的构成,肯定是:

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

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

    所以此时答案应该是

    [n! - lfloor frac{n}{2} floor ! imes prod_{i=0}^{25} cnt[i] ! ]

    修改后正确的想法

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

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

    所以答案应该是

    [n! - lfloor frac{n}{2} floor ! imes prod_{i=0}^{25} frac{cnt[i]!}{lfloor frac{cnt[i]}{2} floor !} ]

    实现代码如下:

    #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;
    }
    
  • 相关阅读:
    DFS+输出路线--poj2488--A Knight's Journey
    三:矩阵快速幂应用
    二:矩阵快速幂
    一:快速求幂
    动态规划空间复杂度的优化--滚动数组
    暴力--全排列+排列组合+组合(求子集)
    next_permutation 与 prev_permutation(全排列算法)
    BFS入门--POJ3278--抓羊
    java基础编程题
    计蒜客
  • 原文地址:https://www.cnblogs.com/quanjun/p/12396279.html
Copyright © 2011-2022 走看看