1 条题解

  • 0
    @ 2026-10-19 0:36:25

    [CSP-J 2019 江西] 非回文串

    知识点

    组合计数、阶乘、乘法逆元、回文

    解题思路

    题目计算的是下标排列,故总数是n!,相同字符的位置仍不同。统计26种字符的次数c。若奇数次数的种类超过1,不能形成回文,答案即n!。否则先把每种字符的一半放入左半段,可得到(n/2)!/∏(c/2)!种回文字符串;每种字符串可以为每种字符安排c!种原下标,乘上∏c!即得到回文下标排列数。用总数减去此数,模质数计算。

    正确性说明

    回文的对称位置必须字符相同,所以至多一种字符次数为奇数。满足此条件时,中间字符唯一确定,左半段的多重集合排列与回文字符串一一对应。对固定字符串,某字符的c个不同原下标能以c!种方式安排到其位置,互相独立。故上述乘积恰好计入所有回文下标排列;从全部n!个排列中减去即为非回文数量。

    易错点

    样例aba的答案为4,不是不同非回文字符串的数量;模除法使用逆元;相减后加模数防负。

    复杂度

    预处理阶乘O(n+log MOD),统计O(n),空间O(n)。

    参考代码(GNU C++17)

    #include<bits/stdc++.h>
    using namespace std;
    const long long MOD=1000000007;long long pw(long long a,long long b){long long r=1;for(;b;b>>=1,a=a*a%MOD)if(b&1)r=r*a%MOD;return r;}
    int main(){ios::sync_with_stdio(false);cin.tie(nullptr);int n;cin>>n;int c[26]={};for(int i=0;i<n;i++){char x;cin>>x;++c[x-'a'];}vector<long long>f(n+1,1);for(int i=1;i<=n;i++)f[i]=f[i-1]*i%MOD;int odd=0;for(int x:c)odd+=x%2;if(odd>1){cout<<f[n]<<'\n';return 0;}long long pal=f[n/2];for(int x:c)pal=pal*pw(f[x/2],MOD-2)%MOD*f[x]%MOD;cout<<(f[n]-pal+MOD)%MOD<<'\n';}
    
    • 1

    信息

    ID
    863
    时间
    1000ms
    内存
    125MiB
    难度
    普及+
    标签
    递交数
    0
    已通过
    0
    上传者